GalaxyCamera.cs 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074
  1. using Cognex.VisionPro;
  2. using GxIAPINET;
  3. using MathNet.Numerics.LinearAlgebra;
  4. using Microsoft.Win32;
  5. using NPOI.Util;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.ComponentModel;
  9. using System.Diagnostics;
  10. using System.Drawing;
  11. using System.Drawing.Imaging;
  12. using System.Runtime.CompilerServices;
  13. using System.Runtime.InteropServices;
  14. using System.Text.RegularExpressions;
  15. using System.Threading;
  16. using System.Threading.Tasks;
  17. using TeamAAS_VP.Core.GalaxyMethod;
  18. using TeamAAS_VP.Enums;
  19. using TeamAAS_VP.Interfaces;
  20. using TeamAAS_VP.Models;
  21. namespace TeamAAS_VP.Core.Cameras
  22. {
  23. public class GalaxyCamera : CameraBase, ICamera, INotifyPropertyChanged
  24. {
  25. #region 字段
  26. private Thread m_hReceiveThread;
  27. static IGXFactory m_objIGXFactory = null; //Factory对像
  28. IGXDevice m_objIGXDevice = null; //设备对像
  29. IGXStream m_objIGXStream = null; //流对像
  30. static List<IGXDeviceInfo> m_listIGXDeviceInfo = new List<IGXDeviceInfo>(); //设备信息列表
  31. IGXFeatureControl m_objIGXFeatureControl = null; //远端设备属性控制器对像
  32. IGXFeatureControl m_objIGXStreamFeatureControl = null; //流层属性控制器对象
  33. IntPtr m_pOutBuffer = IntPtr.Zero; //图像质量提升或图像格式转换输出Buffer
  34. IntPtr m_pBitmapInfo = IntPtr.Zero;
  35. bool m_bIsColor = false; ///<是否支持彩色相机
  36. byte[] m_byMonoBuffer = null; ///<黑白相机buffer
  37. byte[] m_byColorBuffer = null; ///<彩色相机buffer
  38. int m_nWidth = 0; ///<图像宽度
  39. int m_nHeight = 0; ///<图像高度
  40. IGXImageFormatConvert m_objImageFormatConvert = null; ///<IGXImageFormatConvert对象,仅供图像格式转换使用
  41. CWin32Bitmaps.BITMAPINFO m_objBitmapInfo = new CWin32Bitmaps.BITMAPINFO();
  42. #endregion
  43. #region 属性
  44. public string Name { get; private set; }
  45. public Guid ID { get; private set; }
  46. public int Index { get; set; }
  47. public CameraBrand CameraBrand { get => CameraBrand.Galaxy; }
  48. public bool IsFindByIp { get; private set; }
  49. public string ManufacturerName { get; private set; }
  50. public string ModelName { get; private set; }
  51. public string SerialNumber { get; private set; }
  52. public string CameraIp { get; private set; }
  53. public CameraType CameraType { get; private set; }
  54. private bool _IsGrabbing;
  55. /// <summary>
  56. /// 正在采集
  57. /// </summary>
  58. public bool IsGrabbing
  59. {
  60. get { return _IsGrabbing; }
  61. private set { SetProperty(ref _IsGrabbing, value); }
  62. }
  63. private ICogImage _Image;
  64. public ICogImage Image
  65. {
  66. get { return _Image; }
  67. private set { SetProperty(ref _Image, value); }
  68. }
  69. public bool IsConnected { get; private set; }
  70. public TimeSpan TotalTime { get; private set; }
  71. public string ErrorMessage { get; private set; }
  72. public uint ImageWidth { get; private set; }
  73. public uint ImageHeight { get; private set; }
  74. private bool IsHaveCamera = false;
  75. #endregion
  76. #region 事件
  77. public event Action<ICogImage, TimeSpan, string> ImageCallbackEvent;
  78. public event Action<Guid, bool> CameraConnectChangedEvent;
  79. #endregion
  80. public GalaxyCamera(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. var list = GetDevices();
  89. foreach (var device in list)
  90. {
  91. if (device.CameraType== CameraType.GIGE)
  92. {
  93. if (IsFindByIp)
  94. {
  95. if (device.CameraIp == CameraIp)
  96. {
  97. IsHaveCamera = true;
  98. ManufacturerName = device.ManufacturerName;
  99. ModelName = device.Model;
  100. SerialNumber = device.SerialNumber;
  101. CameraType = CameraType.GIGE;
  102. break;
  103. }
  104. }
  105. else
  106. {
  107. if (device.SerialNumber == serialNumber)
  108. {
  109. IsHaveCamera = true;
  110. ManufacturerName = device.ManufacturerName;
  111. ModelName = device.Model;
  112. SerialNumber = device.SerialNumber;
  113. CameraType = CameraType.GIGE;
  114. break;
  115. }
  116. }
  117. }
  118. else
  119. {
  120. if (device.SerialNumber == serialNumber)
  121. {
  122. IsHaveCamera = true;
  123. ManufacturerName = device.ManufacturerName;
  124. ModelName = device.Model;
  125. SerialNumber = device.SerialNumber;
  126. CameraType = CameraType.GIGE;
  127. break;
  128. }
  129. }
  130. }
  131. IsConnected = false;
  132. }
  133. #region 方法
  134. /// <summary>
  135. /// 获取设备
  136. /// </summary>
  137. /// <returns></returns>
  138. public static CameraInfo[] GetDevices()
  139. {
  140. m_objIGXFactory = IGXFactory.GetInstance();
  141. m_objIGXFactory.Init();//相机初始化
  142. List<CameraInfo> cameras = new List<CameraInfo>();
  143. if (!CheckSoftwareInstalled().isInstalled)
  144. {
  145. LogHelper.WriteLogInfo("未安装Galaxy Viewer");
  146. return cameras.ToArray();
  147. }
  148. m_listIGXDeviceInfo.Clear();
  149. if (null != m_objIGXFactory)
  150. {
  151. m_objIGXFactory.UpdateAllDeviceList(200, m_listIGXDeviceInfo);
  152. }
  153. // 判断当前连接设备个数
  154. if (m_listIGXDeviceInfo.Count <= 0)
  155. {
  156. LogHelper.WriteLogInfo("未检测到设备,请确保设备正常连接然后重启程序!");
  157. return cameras.ToArray();
  158. }
  159. for (int i = 0; i < m_listIGXDeviceInfo.Count; i++)
  160. {
  161. var deviceType = m_listIGXDeviceInfo[i].GetDeviceClass();
  162. if (deviceType == GX_DEVICE_CLASS_LIST.GX_DEVICE_CLASS_GEV)
  163. {
  164. cameras.Add(new Models.CameraInfo()
  165. {
  166. CameraNo = i + 1,
  167. CameraName = m_listIGXDeviceInfo[i].GetDisplayName(),
  168. CameraBrand = CameraBrand.Galaxy,
  169. CameraType = CameraType.GIGE,
  170. ManufacturerName = m_listIGXDeviceInfo[i].GetVendorName(),
  171. Model = m_listIGXDeviceInfo[i].GetModelName(),
  172. SerialNumber = m_listIGXDeviceInfo[i].GetSN(),
  173. CameraIp = m_listIGXDeviceInfo[i].GetIP(),
  174. IsFindByIp=true,
  175. });
  176. }
  177. else if (deviceType == GX_DEVICE_CLASS_LIST.GX_DEVICE_CLASS_USB2 || deviceType == GX_DEVICE_CLASS_LIST.GX_DEVICE_CLASS_U3V)
  178. {
  179. cameras.Add(new Models.CameraInfo()
  180. {
  181. CameraNo = i + 1,
  182. CameraName = m_listIGXDeviceInfo[i].GetDisplayName(),
  183. CameraBrand = CameraBrand.Galaxy,
  184. CameraType = CameraType.USB,
  185. ManufacturerName = m_listIGXDeviceInfo[i].GetVendorName(),
  186. Model = m_listIGXDeviceInfo[i].GetModelName(),
  187. SerialNumber = m_listIGXDeviceInfo[i].GetSN(),
  188. CameraIp = "",
  189. });
  190. }
  191. else if (deviceType == GX_DEVICE_CLASS_LIST.GX_DEVICE_CLASS_UNKNOWN)
  192. {
  193. cameras.Add(new Models.CameraInfo()
  194. {
  195. CameraNo = i + 1,
  196. CameraName = m_listIGXDeviceInfo[i].GetDisplayName(),
  197. CameraBrand = CameraBrand.Galaxy,
  198. CameraType = CameraType.Unknown,
  199. ManufacturerName = m_listIGXDeviceInfo[i].GetVendorName(),
  200. Model = m_listIGXDeviceInfo[i].GetModelName(),
  201. SerialNumber = m_listIGXDeviceInfo[i].GetSN(),
  202. CameraIp = "",
  203. });
  204. }
  205. }
  206. return cameras.ToArray();
  207. }
  208. /// <summary>
  209. /// 检查相机软件是否安装
  210. /// </summary>
  211. /// <returns></returns>
  212. public static (bool isInstalled, string version) CheckSoftwareInstalled()
  213. {
  214. string softwareName = "Galaxy";
  215. string softwareVersion = "2.4.2504";
  216. string[] registryPaths = new[]
  217. {
  218. @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
  219. @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
  220. };
  221. foreach (var path in registryPaths)
  222. {
  223. using (RegistryKey key = Registry.LocalMachine.OpenSubKey(path))
  224. {
  225. if (key == null) continue;
  226. foreach (string subKeyName in key.GetSubKeyNames())
  227. {
  228. using (RegistryKey subKey = key.OpenSubKey(subKeyName))
  229. {
  230. string displayName = subKey.GetValue("DisplayName")?.ToString();
  231. if (displayName != null && displayName.Contains(softwareName))
  232. {
  233. string version = subKey.GetValue("DisplayName")?.ToString();
  234. var match = Regex.Match(version, @"\d+(?:\.\d+)+");
  235. if (match.Success)
  236. {
  237. version = match.Value;
  238. }
  239. else
  240. {
  241. continue;
  242. }
  243. Version v1 = new Version(version);
  244. Version v2 = new Version(softwareVersion);
  245. if (v1 >= v2)
  246. {
  247. return (true, version);
  248. }
  249. else
  250. {
  251. return (false, version);
  252. }
  253. }
  254. }
  255. }
  256. }
  257. }
  258. return (false, "");
  259. }
  260. public void CloseDevice()
  261. {
  262. EnterOperation();
  263. try
  264. {
  265. try
  266. {
  267. if (null != m_objIGXFeatureControl)
  268. {
  269. m_objIGXFeatureControl.GetCommandFeature("AcquisitionStop").Execute();
  270. m_objIGXFeatureControl = null;
  271. }
  272. //停止流通道、注销采集回调和关闭流
  273. if (null != m_objIGXStream)
  274. {
  275. m_objIGXStream.StopGrab();
  276. //注销采集回调函数
  277. m_objIGXStream.UnregisterCaptureCallback();
  278. m_objIGXStream.Close();
  279. m_objIGXStream = null;
  280. m_objIGXStreamFeatureControl = null;
  281. }
  282. //关闭设备
  283. if (null != m_objIGXDevice)
  284. {
  285. m_objIGXDevice.Close();
  286. m_objIGXDevice = null;
  287. }
  288. //反初始化
  289. if (null != m_objIGXFactory)
  290. {
  291. m_objIGXFactory.Uninit();
  292. }
  293. }
  294. catch (Exception)
  295. {
  296. }
  297. ReleaseBuffer();
  298. }
  299. finally
  300. {
  301. ExitOperation();
  302. }
  303. }
  304. public float GetExposureTime()
  305. {
  306. EnterOperation();
  307. try
  308. {
  309. if (null != m_objIGXFeatureControl)
  310. {
  311. double dCurShuter = m_objIGXFeatureControl.GetFloatFeature("ExposureTime").GetValue();
  312. return (float)dCurShuter;
  313. }
  314. else
  315. { return 0; }
  316. }
  317. finally
  318. {
  319. ExitOperation();
  320. }
  321. }
  322. public float GetGain()
  323. {
  324. EnterOperation();
  325. try
  326. {
  327. if (null != m_objIGXFeatureControl)
  328. {
  329. double dCurGain = m_objIGXFeatureControl.GetFloatFeature("Gain").GetValue();
  330. return (float)dCurGain;
  331. }
  332. else
  333. { return 0; }
  334. }
  335. finally
  336. {
  337. ExitOperation();
  338. }
  339. }
  340. public ICogImage Grab()
  341. {
  342. EnterOperation();
  343. try
  344. {
  345. IImageData objIImageData = null;
  346. Stopwatch sw = Stopwatch.StartNew();
  347. for (int j = 0; j < 5; j++)
  348. {
  349. try
  350. {
  351. if (null == m_objIGXDevice)
  352. {
  353. OpenDevice();
  354. }
  355. //开启采集流通道
  356. if (null != m_objIGXStream)
  357. {
  358. m_objIGXStream.StartGrab();
  359. }
  360. //发送开采命令
  361. if (null != m_objIGXFeatureControl)
  362. {
  363. m_objIGXFeatureControl.GetCommandFeature("AcquisitionStart").Execute();
  364. }
  365. objIImageData = m_objIGXStream.GetImageNoThrow(500);
  366. //===================================
  367. GX_VALID_BIT_LIST emValidBits = GX_VALID_BIT_LIST.GX_BIT_0_7;
  368. if (null != objIImageData)
  369. {
  370. emValidBits = GetBestValudBit(objIImageData.GetPixelFormat());
  371. if (GX_FRAME_STATUS_LIST.GX_FRAME_STATUS_SUCCESS == objIImageData.GetStatus())
  372. {
  373. if (m_bIsColor)
  374. {
  375. IntPtr pRGB24Buffer = IntPtr.Zero;
  376. if (objIImageData.GetPixelFormat() == GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BGR8)
  377. {
  378. byte[] byColorBufferTmp = new byte[__GetStride(m_nWidth, m_bIsColor) * m_nHeight];
  379. Marshal.Copy(objIImageData.GetBuffer(), byColorBufferTmp, 0, __GetStride(m_nWidth, m_bIsColor) * m_nHeight);
  380. pRGB24Buffer = objIImageData.GetBuffer();
  381. //BGR8格式需要翻转数据后显示
  382. for (int i = 0; i < m_nHeight; i++)
  383. {
  384. Buffer.BlockCopy(byColorBufferTmp, (m_nHeight - i - 1) * m_nWidth * 3, m_byColorBuffer, i * m_nWidth * 3, m_nWidth * 3);
  385. }
  386. }
  387. else
  388. {
  389. // 设置目标像素格式
  390. m_objImageFormatConvert.SetDstFormat(GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BGR8);
  391. // 获取目标像素格式Buffer大小
  392. UInt64 i64DstBufferize = m_objImageFormatConvert.GetBufferSizeForConversion(objIImageData);
  393. // 设置目标有效位数
  394. m_objImageFormatConvert.SetValidBits(emValidBits);
  395. // 进行图像格式转换
  396. m_objImageFormatConvert.Convert(objIImageData, m_pOutBuffer, i64DstBufferize, true);
  397. Marshal.Copy(m_pOutBuffer, m_byColorBuffer, 0, __GetStride(m_nWidth, m_bIsColor) * m_nHeight);
  398. pRGB24Buffer = m_pOutBuffer;
  399. }
  400. Image = ConvertImage((uint)m_nWidth, (uint)m_nHeight, pRGB24Buffer, GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BGR8);
  401. }
  402. else
  403. {
  404. IntPtr pRaw8Buffer = IntPtr.Zero;
  405. if (__IsPixelFormat8(objIImageData.GetPixelFormat()))
  406. {
  407. byte[] byMonoBufferTmp = new byte[__GetStride(m_nWidth, m_bIsColor) * m_nHeight];
  408. Marshal.Copy(objIImageData.GetBuffer(), byMonoBufferTmp, 0, __GetStride(m_nWidth, m_bIsColor) * m_nHeight);
  409. pRaw8Buffer = objIImageData.GetBuffer();
  410. // 黑白相机需要翻转数据后显示
  411. for (int i = 0; i < m_nHeight; i++)
  412. {
  413. Buffer.BlockCopy(byMonoBufferTmp, (m_nHeight - i - 1) * m_nWidth, m_byMonoBuffer, i * m_nWidth, m_nWidth);
  414. }
  415. }
  416. else
  417. {
  418. // 设置目标像素格式
  419. m_objImageFormatConvert.SetDstFormat(GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO8);
  420. // 获取目标像素格式Buffer大小
  421. UInt64 i64DstBufferize = m_objImageFormatConvert.GetBufferSizeForConversion(objIImageData);
  422. // 设置目标有效位数
  423. m_objImageFormatConvert.SetValidBits(emValidBits);
  424. // 进行图像格式转换
  425. m_objImageFormatConvert.Convert(objIImageData, m_pOutBuffer, i64DstBufferize, true);
  426. Marshal.Copy(m_pOutBuffer, m_byMonoBuffer, 0, __GetStride(m_nWidth, m_bIsColor) * m_nHeight);
  427. pRaw8Buffer = m_pOutBuffer;
  428. }
  429. Image = ConvertImage((uint)m_nWidth, (uint)m_nHeight, pRaw8Buffer, GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO8);
  430. }
  431. }
  432. }
  433. if (Image != null)
  434. {
  435. ErrorMessage = "";
  436. TotalTime = sw.Elapsed;
  437. return Image;
  438. }
  439. }
  440. catch (Exception ex)
  441. {
  442. CloseDevice();
  443. OpenDevice();
  444. ErrorMessage = ex.Message;
  445. }
  446. finally
  447. {
  448. if (null != objIImageData)
  449. {
  450. //用完之后释放资源
  451. objIImageData.Destroy();
  452. }
  453. }
  454. }
  455. if (IsConnected)
  456. {
  457. IsConnected = false;
  458. CameraConnectChangedEvent?.Invoke(ID, false);
  459. }
  460. return null;
  461. }
  462. finally
  463. {
  464. ExitOperation();
  465. }
  466. }
  467. public bool OpenDevice()
  468. {
  469. EnterOperation();
  470. try
  471. {
  472. IsConnected = false;
  473. var list = GetDevices();
  474. foreach (var device in list)
  475. {
  476. if (device.CameraType == CameraType.GIGE)
  477. {
  478. if (IsFindByIp)
  479. {
  480. if (device.CameraIp == CameraIp)
  481. {
  482. IsHaveCamera = true;
  483. ManufacturerName = device.ManufacturerName;
  484. ModelName = device.Model;
  485. SerialNumber = device.SerialNumber;
  486. CameraType = CameraType.GIGE;
  487. break;
  488. }
  489. }
  490. else
  491. {
  492. if (device.SerialNumber == SerialNumber)
  493. {
  494. IsHaveCamera = true;
  495. ManufacturerName = device.ManufacturerName;
  496. ModelName = device.Model;
  497. SerialNumber = device.SerialNumber;
  498. CameraType = CameraType.GIGE;
  499. break;
  500. }
  501. }
  502. }
  503. else
  504. {
  505. if (device.SerialNumber == SerialNumber)
  506. {
  507. IsHaveCamera = true;
  508. ManufacturerName = device.ManufacturerName;
  509. ModelName = device.Model;
  510. SerialNumber = device.SerialNumber;
  511. CameraType = CameraType.GIGE;
  512. break;
  513. }
  514. }
  515. }
  516. if (!IsHaveCamera)
  517. {
  518. //throw new Exception("没有发现相机");
  519. return false;
  520. }
  521. // 如果设备已经打开则关闭,保证相机在初始化出错情况下能再次打开
  522. if (null != m_objIGXDevice)
  523. {
  524. m_objIGXDevice.Close();
  525. m_objIGXDevice = null;
  526. }
  527. //打开设备
  528. m_objIGXDevice = m_objIGXFactory.OpenDeviceBySN(SerialNumber, GxIAPINET.GX_ACCESS_MODE.GX_ACCESS_EXCLUSIVE);
  529. m_objIGXFeatureControl = m_objIGXDevice.GetRemoteFeatureControl();
  530. //打开流
  531. if (null != m_objIGXDevice)
  532. {
  533. m_objIGXStream = m_objIGXDevice.OpenStream(0);
  534. m_objIGXStreamFeatureControl = m_objIGXStream.GetFeatureControl();
  535. }
  536. // 建议用户在打开网络相机之后,根据当前网络环境设置相机的流通道包长值,
  537. // 以提高网络相机的采集性能,设置方法参考以下代码。
  538. GX_DEVICE_CLASS_LIST objDeviceClass = m_objIGXDevice.GetDeviceInfo().GetDeviceClass();
  539. if (GX_DEVICE_CLASS_LIST.GX_DEVICE_CLASS_GEV == objDeviceClass)
  540. {
  541. // 判断设备是否支持流通道数据包功能
  542. if (true == m_objIGXFeatureControl.IsImplemented("GevSCPSPacketSize"))
  543. {
  544. // 获取当前网络环境的最优包长值
  545. uint nPacketSize = m_objIGXStream.GetOptimalPacketSize();
  546. // 将最优包长值设置为当前设备的流通道包长值
  547. m_objIGXFeatureControl.GetIntFeature("GevSCPSPacketSize").SetValue(nPacketSize);
  548. }
  549. }
  550. //初始化相机参数
  551. if (null != m_objIGXFeatureControl)
  552. {
  553. //设置采集模式连续采集
  554. m_objIGXFeatureControl.GetEnumFeature("AcquisitionMode").SetValue("Continuous");
  555. //设置触发模式为关
  556. m_objIGXFeatureControl.GetEnumFeature("TriggerMode").SetValue("Off");
  557. }
  558. ReleaseBuffer();
  559. GxBitmap();
  560. if (null != m_objIGXStreamFeatureControl)
  561. {
  562. try
  563. {
  564. //设置流层Buffer处理模式为OldestFirst
  565. m_objIGXStreamFeatureControl.GetEnumFeature("StreamBufferHandlingMode").SetValue("OldestFirst");
  566. }
  567. catch (Exception)
  568. {
  569. }
  570. }
  571. if (!IsConnected)
  572. {
  573. CameraConnectChangedEvent?.Invoke(ID, true);
  574. }
  575. IsConnected = true;
  576. return IsConnected;
  577. }
  578. finally
  579. {
  580. ExitOperation();
  581. }
  582. }
  583. /// <summary>
  584. /// 打开相机异步
  585. /// </summary>
  586. /// <returns></returns>
  587. public Task<bool> OpenDeviceAsync()
  588. {
  589. return Task.Run(() =>
  590. {
  591. return OpenDevice();
  592. });
  593. }
  594. public bool SetExposureTime(float ExposureTime)
  595. {
  596. EnterOperation();
  597. try
  598. {
  599. if (null == m_objIGXFeatureControl)
  600. return false;
  601. if (GetExposureTime() != ExposureTime)
  602. {
  603. bool success = false;
  604. for (int i = 0; i < 5; i++)
  605. {
  606. m_objIGXFeatureControl.GetFloatFeature("ExposureTime").SetValue(ExposureTime);
  607. success = true;
  608. }
  609. return success;
  610. }
  611. return true;
  612. }
  613. finally
  614. {
  615. ExitOperation();
  616. }
  617. }
  618. public bool SetGain(float Gain)
  619. {
  620. EnterOperation();
  621. try
  622. {
  623. if (null == m_objIGXFeatureControl)
  624. return false;
  625. if (GetGain() != Gain)
  626. {
  627. bool success = false;
  628. for (int i = 0; i < 5; i++)
  629. {
  630. m_objIGXFeatureControl.GetFloatFeature("Gain").SetValue(Gain);
  631. success = true;
  632. }
  633. return success;
  634. }
  635. return true;
  636. }
  637. finally
  638. {
  639. ExitOperation();
  640. }
  641. }
  642. public void StartGrabbing()
  643. {
  644. lock (_stateLock)
  645. {
  646. if (IsGrabbing)
  647. return;
  648. IsGrabbing = true;
  649. }
  650. m_hReceiveThread = new Thread(GetStreamThreadProc) { IsBackground = true };
  651. m_hReceiveThread.Start();
  652. }
  653. public void StopGrabbing()
  654. {
  655. try
  656. {
  657. lock (_stateLock)
  658. {
  659. IsGrabbing = false;
  660. }
  661. Thread.Sleep(1000);
  662. if (m_hReceiveThread != null)
  663. {
  664. m_hReceiveThread.Abort();
  665. m_hReceiveThread = null;
  666. }
  667. }
  668. catch (Exception)
  669. {
  670. }
  671. }
  672. private void GetStreamThreadProc()
  673. {
  674. while (IsGrabbing)
  675. {
  676. try
  677. {
  678. Grab();
  679. ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage);
  680. }
  681. catch (Exception)
  682. {
  683. }
  684. Thread.Sleep(10);
  685. }
  686. IsGrabbing = false;
  687. }
  688. #endregion
  689. #region method
  690. /// <summary>
  691. /// 初始化设备对象
  692. /// </summary>
  693. /// <param name="objIGXDevice">设备对象</param>
  694. public void GxBitmap()
  695. {
  696. // 初始化图像格式转换对象
  697. m_objImageFormatConvert = m_objIGXFactory.CreateImageFormatConvert();
  698. if (null != m_objIGXDevice)
  699. {
  700. m_nWidth = (int)m_objIGXDevice.GetRemoteFeatureControl().GetIntFeature("Width").GetValue();
  701. m_nHeight = (int)m_objIGXDevice.GetRemoteFeatureControl().GetIntFeature("Height").GetValue();
  702. ImageWidth = (uint)m_nWidth;
  703. ImageHeight = (uint)m_nHeight;
  704. //获取是否为彩色相机
  705. IsSupportColor(ref m_bIsColor);
  706. }
  707. //申请用于缓存图像数据的buffer
  708. m_byMonoBuffer = new byte[__GetStride(m_nWidth, m_bIsColor) * m_nHeight];
  709. m_byColorBuffer = new byte[__GetStride(m_nWidth, m_bIsColor) * m_nHeight];
  710. m_pOutBuffer = Marshal.AllocCoTaskMem(__GetStride(m_nWidth, m_bIsColor) * m_nHeight);
  711. if (m_bIsColor)
  712. {
  713. m_objBitmapInfo.bmiHeader.biSize = (uint)Marshal.SizeOf(typeof(CWin32Bitmaps.BITMAPINFOHEADER));
  714. m_objBitmapInfo.bmiHeader.biWidth = m_nWidth;
  715. m_objBitmapInfo.bmiHeader.biHeight = m_nHeight;
  716. m_objBitmapInfo.bmiHeader.biPlanes = 1;
  717. m_objBitmapInfo.bmiHeader.biBitCount = 24;
  718. m_objBitmapInfo.bmiHeader.biCompression = 0;
  719. m_objBitmapInfo.bmiHeader.biSizeImage = 0;
  720. m_objBitmapInfo.bmiHeader.biXPelsPerMeter = 0;
  721. m_objBitmapInfo.bmiHeader.biYPelsPerMeter = 0;
  722. m_objBitmapInfo.bmiHeader.biClrUsed = 0;
  723. m_objBitmapInfo.bmiHeader.biClrImportant = 0;
  724. }
  725. else
  726. {
  727. m_objBitmapInfo.bmiHeader.biSize = (uint)Marshal.SizeOf(typeof(CWin32Bitmaps.BITMAPINFOHEADER));
  728. m_objBitmapInfo.bmiHeader.biWidth = m_nWidth;
  729. m_objBitmapInfo.bmiHeader.biHeight = m_nHeight;
  730. m_objBitmapInfo.bmiHeader.biPlanes = 1;
  731. m_objBitmapInfo.bmiHeader.biBitCount = 8;
  732. m_objBitmapInfo.bmiHeader.biCompression = 0;
  733. m_objBitmapInfo.bmiHeader.biSizeImage = 0;
  734. m_objBitmapInfo.bmiHeader.biXPelsPerMeter = 0;
  735. m_objBitmapInfo.bmiHeader.biYPelsPerMeter = 0;
  736. m_objBitmapInfo.bmiHeader.biClrUsed = 0;
  737. m_objBitmapInfo.bmiHeader.biClrImportant = 0;
  738. m_objBitmapInfo.bmiColors = new CWin32Bitmaps.RGBQUAD[256];
  739. // 黑白图像需要初始化调色板
  740. for (int i = 0; i < 256; i++)
  741. {
  742. m_objBitmapInfo.bmiColors[i].rgbBlue = (byte)i;
  743. m_objBitmapInfo.bmiColors[i].rgbGreen = (byte)i;
  744. m_objBitmapInfo.bmiColors[i].rgbRed = (byte)i;
  745. m_objBitmapInfo.bmiColors[i].rgbReserved = 0;
  746. }
  747. }
  748. m_pBitmapInfo = Marshal.AllocHGlobal(2048);
  749. Marshal.StructureToPtr(m_objBitmapInfo, m_pBitmapInfo, false);
  750. }
  751. /// <summary>
  752. /// 释放buffer
  753. /// </summary>
  754. public void ReleaseBuffer()
  755. {
  756. // 释放输出Buffer内存
  757. if (m_pOutBuffer != IntPtr.Zero)
  758. {
  759. Marshal.FreeCoTaskMem(m_pOutBuffer);
  760. m_pOutBuffer = IntPtr.Zero;
  761. }
  762. if (m_pBitmapInfo != IntPtr.Zero)
  763. {
  764. Marshal.FreeHGlobal(m_pBitmapInfo);
  765. m_pBitmapInfo = IntPtr.Zero;
  766. }
  767. }
  768. /// <summary>
  769. /// 是否支持彩色
  770. /// </summary>
  771. /// <param name="bIsColorFilter">是否支持彩色</param>
  772. public void IsSupportColor(ref bool bIsColorFilter)
  773. {
  774. bool bIsImplemented = false;
  775. bool bIsMono = false;
  776. string strPixelFormat = "";
  777. uint nPixelFormatValue = 0;
  778. strPixelFormat = m_objIGXDevice.GetRemoteFeatureControl().GetEnumFeature("PixelFormat").GetValue();
  779. if (0 == string.Compare(strPixelFormat, 0, "Mono", 0, 4))
  780. {
  781. bIsMono = true;
  782. }
  783. else
  784. {
  785. bIsMono = false;
  786. }
  787. // 通过当前像素格式判断是否为彩色相机
  788. CDecide.GetConvertPixelFormat(strPixelFormat, ref nPixelFormatValue);
  789. bIsImplemented = CDecide.GetIsGray(nPixelFormatValue);
  790. if ((!bIsMono) && (!bIsImplemented))
  791. {
  792. bIsColorFilter = true;
  793. }
  794. else
  795. {
  796. bIsColorFilter = false;
  797. }
  798. }
  799. /// <summary>
  800. /// 计算宽度所占的字节数
  801. /// </summary>
  802. /// <param name="nWidth">图像宽度</param>
  803. /// <param name="bIsColor">是否是彩色相机</param>
  804. /// <returns>图像一行所占的字节数</returns>
  805. private int __GetStride(int nWidth, bool bIsColor)
  806. {
  807. return bIsColor ? nWidth * 3 : nWidth;
  808. }
  809. /// <summary>
  810. /// 通过GX_PIXEL_FORMAT_ENTRY获取最优Bit位
  811. /// </summary>
  812. /// <param name="em">图像数据格式</param>
  813. /// <returns>最优Bit位</returns>
  814. public GX_VALID_BIT_LIST GetBestValudBit(GX_PIXEL_FORMAT_ENTRY emPixelFormatEntry)
  815. {
  816. GX_VALID_BIT_LIST emValidBits = GX_VALID_BIT_LIST.GX_BIT_0_7;
  817. switch (emPixelFormatEntry)
  818. {
  819. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO8:
  820. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR8:
  821. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG8:
  822. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB8:
  823. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG8:
  824. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_RGB8:
  825. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BGR8:
  826. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_R8:
  827. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_G8:
  828. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_B8:
  829. {
  830. emValidBits = GX_VALID_BIT_LIST.GX_BIT_0_7;
  831. break;
  832. }
  833. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO10:
  834. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO10_P:
  835. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO10_PACKED:
  836. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR10:
  837. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG10:
  838. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB10:
  839. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG10:
  840. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG10_P:
  841. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG10_PACKED:
  842. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB10_P:
  843. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB10_PACKED:
  844. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR10_P:
  845. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR10_PACKED:
  846. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG10_P:
  847. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG10_PACKED:
  848. {
  849. emValidBits = GX_VALID_BIT_LIST.GX_BIT_2_9;
  850. break;
  851. }
  852. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO12:
  853. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO12_P:
  854. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO12_PACKED:
  855. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR12:
  856. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG12:
  857. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB12:
  858. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG12:
  859. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG12_P:
  860. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG12_PACKED:
  861. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB12_P:
  862. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB12_PACKED:
  863. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR12_P:
  864. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR12_PACKED:
  865. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG12_P:
  866. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG12_PACKED:
  867. {
  868. emValidBits = GX_VALID_BIT_LIST.GX_BIT_4_11;
  869. break;
  870. }
  871. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO14:
  872. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR14:
  873. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG14:
  874. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB14:
  875. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG14:
  876. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG14_P:
  877. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB14_P:
  878. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR14_P:
  879. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG14_P:
  880. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO14_P:
  881. {
  882. emValidBits = GX_VALID_BIT_LIST.GX_BIT_6_13;
  883. break;
  884. }
  885. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO16:
  886. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR16:
  887. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG16:
  888. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB16:
  889. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG16:
  890. {
  891. emValidBits = GX_VALID_BIT_LIST.GX_BIT_8_15;
  892. break;
  893. }
  894. default:
  895. break;
  896. }
  897. return emValidBits;
  898. }
  899. /// <summary>
  900. /// 判断PixelFormat是否为8位
  901. /// </summary>
  902. /// <param name="emPixelFormatEntry">图像数据格式</param>
  903. /// <returns>true为8为数据,false为非8位数据</returns>
  904. private bool __IsPixelFormat8(GX_PIXEL_FORMAT_ENTRY emPixelFormatEntry)
  905. {
  906. const uint PIXEL_FORMATE_BIT = 0x00FF0000; //用于与当前的数据格式进行与运算得到当前的数据位数
  907. const uint GX_PIXEL_8BIT = 0x00080000; //8位数据图像格式
  908. bool bIsPixelFormat8 = false;
  909. uint uiPixelFormatEntry = (uint)emPixelFormatEntry;
  910. if ((uiPixelFormatEntry & PIXEL_FORMATE_BIT) == GX_PIXEL_8BIT)
  911. {
  912. bIsPixelFormat8 = true;
  913. }
  914. return bIsPixelFormat8;
  915. }
  916. /// <summary>
  917. /// 转换图片
  918. /// </summary>
  919. /// <param name="nHeight">高</param>
  920. /// <param name="nWidth">宽</param>
  921. /// <param name="pImageBuf">图片数据</param>
  922. /// <param name="enPixelType">像素格式</param>
  923. public ICogImage ConvertImage(UInt32 nWidth, UInt32 nHeight, IntPtr pImageBuf, GX_PIXEL_FORMAT_ENTRY enPixelType)
  924. {
  925. try
  926. {
  927. if (enPixelType == GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO8)
  928. {
  929. CogImage8Root cogImage8Root = new CogImage8Root();
  930. cogImage8Root.Initialize((Int32)nWidth, (Int32)nHeight, pImageBuf, (Int32)nWidth, null);
  931. CogImage8Grey cogImage8Grey = new CogImage8Grey();
  932. cogImage8Grey.SetRoot(cogImage8Root);
  933. var image = cogImage8Grey.ScaleImage((int)nWidth, (int)nHeight);
  934. System.GC.Collect();
  935. return image;
  936. }
  937. else
  938. {
  939. int stride = (int)nWidth * 3;
  940. CogImage24PlanarColor cogImage24PlanarColor = new CogImage24PlanarColor(new Bitmap((int)nWidth, (int)nHeight, stride, PixelFormat.Format24bppRgb, pImageBuf));
  941. var m_InputImageRgb24 = cogImage24PlanarColor.Copy(CogImageCopyModeConstants.CopyPixels);
  942. return m_InputImageRgb24;
  943. }
  944. }
  945. catch (System.Exception)
  946. {
  947. return null;
  948. }
  949. }
  950. #endregion
  951. #region 属性通知
  952. /// <summary>
  953. /// Occurs when a property value changes.
  954. /// </summary>
  955. public event PropertyChangedEventHandler PropertyChanged;
  956. /// <summary>
  957. /// Checks if a property already matches a desired value. Sets the property and
  958. /// notifies listeners only when necessary.
  959. /// </summary>
  960. /// <typeparam name="T">Type of the property.</typeparam>
  961. /// <param name="storage">Reference to a property with both getter and setter.</param>
  962. /// <param name="value">Desired value for the property.</param>
  963. /// <param name="propertyName">Name of the property used to notify listeners. This
  964. /// value is optional and can be provided automatically when invoked from compilers that
  965. /// support CallerMemberName.</param>
  966. /// <returns>True if the value was changed, false if the existing value matched the
  967. /// desired value.</returns>
  968. protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
  969. {
  970. if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
  971. storage = value;
  972. RaisePropertyChanged(propertyName);
  973. return true;
  974. }
  975. /// <summary>
  976. /// Checks if a property already matches a desired value. Sets the property and
  977. /// notifies listeners only when necessary.
  978. /// </summary>
  979. /// <typeparam name="T">Type of the property.</typeparam>
  980. /// <param name="storage">Reference to a property with both getter and setter.</param>
  981. /// <param name="value">Desired value for the property.</param>
  982. /// <param name="propertyName">Name of the property used to notify listeners. This
  983. /// value is optional and can be provided automatically when invoked from compilers that
  984. /// support CallerMemberName.</param>
  985. /// <param name="onChanged">Action that is called after the property value has been changed.</param>
  986. /// <returns>True if the value was changed, false if the existing value matched the
  987. /// desired value.</returns>
  988. protected virtual bool SetProperty<T>(ref T storage, T value, Action onChanged, [CallerMemberName] string propertyName = null)
  989. {
  990. if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
  991. storage = value;
  992. onChanged?.Invoke();
  993. RaisePropertyChanged(propertyName);
  994. return true;
  995. }
  996. /// <summary>
  997. /// Raises this object's PropertyChanged event.
  998. /// </summary>
  999. /// <param name="propertyName">Name of the property used to notify listeners. This
  1000. /// value is optional and can be provided automatically when invoked from compilers
  1001. /// that support <see cref="CallerMemberNameAttribute"/>.</param>
  1002. protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
  1003. {
  1004. OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
  1005. }
  1006. /// <summary>
  1007. /// Raises this object's PropertyChanged event.
  1008. /// </summary>
  1009. /// <param name="args">The PropertyChangedEventArgs</param>
  1010. protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
  1011. {
  1012. PropertyChanged?.Invoke(this, args);
  1013. }
  1014. #endregion
  1015. }
  1016. }