GalaxyCamera.cs 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079
  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. /// <summary>
  341. /// 采集单张图片
  342. /// </summary>
  343. /// <param name="lastImageOnly">true:采集一张新图像,false:返回最后一张图像</param>
  344. /// <returns></returns>
  345. public ICogImage Grab(bool lastImageOnly = true)
  346. {
  347. EnterOperation();
  348. try
  349. {
  350. IImageData objIImageData = null;
  351. Stopwatch sw = Stopwatch.StartNew();
  352. for (int j = 0; j < 5; j++)
  353. {
  354. try
  355. {
  356. if (null == m_objIGXDevice)
  357. {
  358. OpenDevice();
  359. }
  360. //开启采集流通道
  361. if (null != m_objIGXStream)
  362. {
  363. m_objIGXStream.StartGrab();
  364. }
  365. //发送开采命令
  366. if (null != m_objIGXFeatureControl)
  367. {
  368. m_objIGXFeatureControl.GetCommandFeature("AcquisitionStart").Execute();
  369. }
  370. objIImageData = m_objIGXStream.GetImageNoThrow(500);
  371. //===================================
  372. GX_VALID_BIT_LIST emValidBits = GX_VALID_BIT_LIST.GX_BIT_0_7;
  373. if (null != objIImageData)
  374. {
  375. emValidBits = GetBestValudBit(objIImageData.GetPixelFormat());
  376. if (GX_FRAME_STATUS_LIST.GX_FRAME_STATUS_SUCCESS == objIImageData.GetStatus())
  377. {
  378. if (m_bIsColor)
  379. {
  380. IntPtr pRGB24Buffer = IntPtr.Zero;
  381. if (objIImageData.GetPixelFormat() == GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BGR8)
  382. {
  383. byte[] byColorBufferTmp = new byte[__GetStride(m_nWidth, m_bIsColor) * m_nHeight];
  384. Marshal.Copy(objIImageData.GetBuffer(), byColorBufferTmp, 0, __GetStride(m_nWidth, m_bIsColor) * m_nHeight);
  385. pRGB24Buffer = objIImageData.GetBuffer();
  386. //BGR8格式需要翻转数据后显示
  387. for (int i = 0; i < m_nHeight; i++)
  388. {
  389. Buffer.BlockCopy(byColorBufferTmp, (m_nHeight - i - 1) * m_nWidth * 3, m_byColorBuffer, i * m_nWidth * 3, m_nWidth * 3);
  390. }
  391. }
  392. else
  393. {
  394. // 设置目标像素格式
  395. m_objImageFormatConvert.SetDstFormat(GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BGR8);
  396. // 获取目标像素格式Buffer大小
  397. UInt64 i64DstBufferize = m_objImageFormatConvert.GetBufferSizeForConversion(objIImageData);
  398. // 设置目标有效位数
  399. m_objImageFormatConvert.SetValidBits(emValidBits);
  400. // 进行图像格式转换
  401. m_objImageFormatConvert.Convert(objIImageData, m_pOutBuffer, i64DstBufferize, true);
  402. Marshal.Copy(m_pOutBuffer, m_byColorBuffer, 0, __GetStride(m_nWidth, m_bIsColor) * m_nHeight);
  403. pRGB24Buffer = m_pOutBuffer;
  404. }
  405. Image = ConvertImage((uint)m_nWidth, (uint)m_nHeight, pRGB24Buffer, GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BGR8);
  406. }
  407. else
  408. {
  409. IntPtr pRaw8Buffer = IntPtr.Zero;
  410. if (__IsPixelFormat8(objIImageData.GetPixelFormat()))
  411. {
  412. byte[] byMonoBufferTmp = new byte[__GetStride(m_nWidth, m_bIsColor) * m_nHeight];
  413. Marshal.Copy(objIImageData.GetBuffer(), byMonoBufferTmp, 0, __GetStride(m_nWidth, m_bIsColor) * m_nHeight);
  414. pRaw8Buffer = objIImageData.GetBuffer();
  415. // 黑白相机需要翻转数据后显示
  416. for (int i = 0; i < m_nHeight; i++)
  417. {
  418. Buffer.BlockCopy(byMonoBufferTmp, (m_nHeight - i - 1) * m_nWidth, m_byMonoBuffer, i * m_nWidth, m_nWidth);
  419. }
  420. }
  421. else
  422. {
  423. // 设置目标像素格式
  424. m_objImageFormatConvert.SetDstFormat(GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO8);
  425. // 获取目标像素格式Buffer大小
  426. UInt64 i64DstBufferize = m_objImageFormatConvert.GetBufferSizeForConversion(objIImageData);
  427. // 设置目标有效位数
  428. m_objImageFormatConvert.SetValidBits(emValidBits);
  429. // 进行图像格式转换
  430. m_objImageFormatConvert.Convert(objIImageData, m_pOutBuffer, i64DstBufferize, true);
  431. Marshal.Copy(m_pOutBuffer, m_byMonoBuffer, 0, __GetStride(m_nWidth, m_bIsColor) * m_nHeight);
  432. pRaw8Buffer = m_pOutBuffer;
  433. }
  434. Image = ConvertImage((uint)m_nWidth, (uint)m_nHeight, pRaw8Buffer, GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO8);
  435. }
  436. }
  437. }
  438. if (Image != null)
  439. {
  440. ErrorMessage = "";
  441. TotalTime = sw.Elapsed;
  442. return Image;
  443. }
  444. }
  445. catch (Exception ex)
  446. {
  447. CloseDevice();
  448. OpenDevice();
  449. ErrorMessage = ex.Message;
  450. }
  451. finally
  452. {
  453. if (null != objIImageData)
  454. {
  455. //用完之后释放资源
  456. objIImageData.Destroy();
  457. }
  458. }
  459. }
  460. if (IsConnected)
  461. {
  462. IsConnected = false;
  463. CameraConnectChangedEvent?.Invoke(ID, false);
  464. }
  465. return null;
  466. }
  467. finally
  468. {
  469. ExitOperation();
  470. }
  471. }
  472. public bool OpenDevice()
  473. {
  474. EnterOperation();
  475. try
  476. {
  477. IsConnected = false;
  478. var list = GetDevices();
  479. foreach (var device in list)
  480. {
  481. if (device.CameraType == CameraType.GIGE)
  482. {
  483. if (IsFindByIp)
  484. {
  485. if (device.CameraIp == CameraIp)
  486. {
  487. IsHaveCamera = true;
  488. ManufacturerName = device.ManufacturerName;
  489. ModelName = device.Model;
  490. SerialNumber = device.SerialNumber;
  491. CameraType = CameraType.GIGE;
  492. break;
  493. }
  494. }
  495. else
  496. {
  497. if (device.SerialNumber == SerialNumber)
  498. {
  499. IsHaveCamera = true;
  500. ManufacturerName = device.ManufacturerName;
  501. ModelName = device.Model;
  502. SerialNumber = device.SerialNumber;
  503. CameraType = CameraType.GIGE;
  504. break;
  505. }
  506. }
  507. }
  508. else
  509. {
  510. if (device.SerialNumber == SerialNumber)
  511. {
  512. IsHaveCamera = true;
  513. ManufacturerName = device.ManufacturerName;
  514. ModelName = device.Model;
  515. SerialNumber = device.SerialNumber;
  516. CameraType = CameraType.GIGE;
  517. break;
  518. }
  519. }
  520. }
  521. if (!IsHaveCamera)
  522. {
  523. //throw new Exception("没有发现相机");
  524. return false;
  525. }
  526. // 如果设备已经打开则关闭,保证相机在初始化出错情况下能再次打开
  527. if (null != m_objIGXDevice)
  528. {
  529. m_objIGXDevice.Close();
  530. m_objIGXDevice = null;
  531. }
  532. //打开设备
  533. m_objIGXDevice = m_objIGXFactory.OpenDeviceBySN(SerialNumber, GxIAPINET.GX_ACCESS_MODE.GX_ACCESS_EXCLUSIVE);
  534. m_objIGXFeatureControl = m_objIGXDevice.GetRemoteFeatureControl();
  535. //打开流
  536. if (null != m_objIGXDevice)
  537. {
  538. m_objIGXStream = m_objIGXDevice.OpenStream(0);
  539. m_objIGXStreamFeatureControl = m_objIGXStream.GetFeatureControl();
  540. }
  541. // 建议用户在打开网络相机之后,根据当前网络环境设置相机的流通道包长值,
  542. // 以提高网络相机的采集性能,设置方法参考以下代码。
  543. GX_DEVICE_CLASS_LIST objDeviceClass = m_objIGXDevice.GetDeviceInfo().GetDeviceClass();
  544. if (GX_DEVICE_CLASS_LIST.GX_DEVICE_CLASS_GEV == objDeviceClass)
  545. {
  546. // 判断设备是否支持流通道数据包功能
  547. if (true == m_objIGXFeatureControl.IsImplemented("GevSCPSPacketSize"))
  548. {
  549. // 获取当前网络环境的最优包长值
  550. uint nPacketSize = m_objIGXStream.GetOptimalPacketSize();
  551. // 将最优包长值设置为当前设备的流通道包长值
  552. m_objIGXFeatureControl.GetIntFeature("GevSCPSPacketSize").SetValue(nPacketSize);
  553. }
  554. }
  555. //初始化相机参数
  556. if (null != m_objIGXFeatureControl)
  557. {
  558. //设置采集模式连续采集
  559. m_objIGXFeatureControl.GetEnumFeature("AcquisitionMode").SetValue("Continuous");
  560. //设置触发模式为关
  561. m_objIGXFeatureControl.GetEnumFeature("TriggerMode").SetValue("Off");
  562. }
  563. ReleaseBuffer();
  564. GxBitmap();
  565. if (null != m_objIGXStreamFeatureControl)
  566. {
  567. try
  568. {
  569. //设置流层Buffer处理模式为OldestFirst
  570. m_objIGXStreamFeatureControl.GetEnumFeature("StreamBufferHandlingMode").SetValue("OldestFirst");
  571. }
  572. catch (Exception)
  573. {
  574. }
  575. }
  576. if (!IsConnected)
  577. {
  578. CameraConnectChangedEvent?.Invoke(ID, true);
  579. }
  580. IsConnected = true;
  581. return IsConnected;
  582. }
  583. finally
  584. {
  585. ExitOperation();
  586. }
  587. }
  588. /// <summary>
  589. /// 打开相机异步
  590. /// </summary>
  591. /// <returns></returns>
  592. public Task<bool> OpenDeviceAsync()
  593. {
  594. return Task.Run(() =>
  595. {
  596. return OpenDevice();
  597. });
  598. }
  599. public bool SetExposureTime(float ExposureTime)
  600. {
  601. EnterOperation();
  602. try
  603. {
  604. if (null == m_objIGXFeatureControl)
  605. return false;
  606. if (GetExposureTime() != ExposureTime)
  607. {
  608. bool success = false;
  609. for (int i = 0; i < 5; i++)
  610. {
  611. m_objIGXFeatureControl.GetFloatFeature("ExposureTime").SetValue(ExposureTime);
  612. success = true;
  613. }
  614. return success;
  615. }
  616. return true;
  617. }
  618. finally
  619. {
  620. ExitOperation();
  621. }
  622. }
  623. public bool SetGain(float Gain)
  624. {
  625. EnterOperation();
  626. try
  627. {
  628. if (null == m_objIGXFeatureControl)
  629. return false;
  630. if (GetGain() != Gain)
  631. {
  632. bool success = false;
  633. for (int i = 0; i < 5; i++)
  634. {
  635. m_objIGXFeatureControl.GetFloatFeature("Gain").SetValue(Gain);
  636. success = true;
  637. }
  638. return success;
  639. }
  640. return true;
  641. }
  642. finally
  643. {
  644. ExitOperation();
  645. }
  646. }
  647. public void StartGrabbing()
  648. {
  649. lock (_stateLock)
  650. {
  651. if (IsGrabbing)
  652. return;
  653. IsGrabbing = true;
  654. }
  655. m_hReceiveThread = new Thread(GetStreamThreadProc) { IsBackground = true };
  656. m_hReceiveThread.Start();
  657. }
  658. public void StopGrabbing()
  659. {
  660. try
  661. {
  662. lock (_stateLock)
  663. {
  664. IsGrabbing = false;
  665. }
  666. Thread.Sleep(1000);
  667. if (m_hReceiveThread != null)
  668. {
  669. m_hReceiveThread.Abort();
  670. m_hReceiveThread = null;
  671. }
  672. }
  673. catch (Exception)
  674. {
  675. }
  676. }
  677. private void GetStreamThreadProc()
  678. {
  679. while (IsGrabbing)
  680. {
  681. try
  682. {
  683. Grab();
  684. ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage);
  685. }
  686. catch (Exception)
  687. {
  688. }
  689. Thread.Sleep(10);
  690. }
  691. IsGrabbing = false;
  692. }
  693. #endregion
  694. #region method
  695. /// <summary>
  696. /// 初始化设备对象
  697. /// </summary>
  698. /// <param name="objIGXDevice">设备对象</param>
  699. public void GxBitmap()
  700. {
  701. // 初始化图像格式转换对象
  702. m_objImageFormatConvert = m_objIGXFactory.CreateImageFormatConvert();
  703. if (null != m_objIGXDevice)
  704. {
  705. m_nWidth = (int)m_objIGXDevice.GetRemoteFeatureControl().GetIntFeature("Width").GetValue();
  706. m_nHeight = (int)m_objIGXDevice.GetRemoteFeatureControl().GetIntFeature("Height").GetValue();
  707. ImageWidth = (uint)m_nWidth;
  708. ImageHeight = (uint)m_nHeight;
  709. //获取是否为彩色相机
  710. IsSupportColor(ref m_bIsColor);
  711. }
  712. //申请用于缓存图像数据的buffer
  713. m_byMonoBuffer = new byte[__GetStride(m_nWidth, m_bIsColor) * m_nHeight];
  714. m_byColorBuffer = new byte[__GetStride(m_nWidth, m_bIsColor) * m_nHeight];
  715. m_pOutBuffer = Marshal.AllocCoTaskMem(__GetStride(m_nWidth, m_bIsColor) * m_nHeight);
  716. if (m_bIsColor)
  717. {
  718. m_objBitmapInfo.bmiHeader.biSize = (uint)Marshal.SizeOf(typeof(CWin32Bitmaps.BITMAPINFOHEADER));
  719. m_objBitmapInfo.bmiHeader.biWidth = m_nWidth;
  720. m_objBitmapInfo.bmiHeader.biHeight = m_nHeight;
  721. m_objBitmapInfo.bmiHeader.biPlanes = 1;
  722. m_objBitmapInfo.bmiHeader.biBitCount = 24;
  723. m_objBitmapInfo.bmiHeader.biCompression = 0;
  724. m_objBitmapInfo.bmiHeader.biSizeImage = 0;
  725. m_objBitmapInfo.bmiHeader.biXPelsPerMeter = 0;
  726. m_objBitmapInfo.bmiHeader.biYPelsPerMeter = 0;
  727. m_objBitmapInfo.bmiHeader.biClrUsed = 0;
  728. m_objBitmapInfo.bmiHeader.biClrImportant = 0;
  729. }
  730. else
  731. {
  732. m_objBitmapInfo.bmiHeader.biSize = (uint)Marshal.SizeOf(typeof(CWin32Bitmaps.BITMAPINFOHEADER));
  733. m_objBitmapInfo.bmiHeader.biWidth = m_nWidth;
  734. m_objBitmapInfo.bmiHeader.biHeight = m_nHeight;
  735. m_objBitmapInfo.bmiHeader.biPlanes = 1;
  736. m_objBitmapInfo.bmiHeader.biBitCount = 8;
  737. m_objBitmapInfo.bmiHeader.biCompression = 0;
  738. m_objBitmapInfo.bmiHeader.biSizeImage = 0;
  739. m_objBitmapInfo.bmiHeader.biXPelsPerMeter = 0;
  740. m_objBitmapInfo.bmiHeader.biYPelsPerMeter = 0;
  741. m_objBitmapInfo.bmiHeader.biClrUsed = 0;
  742. m_objBitmapInfo.bmiHeader.biClrImportant = 0;
  743. m_objBitmapInfo.bmiColors = new CWin32Bitmaps.RGBQUAD[256];
  744. // 黑白图像需要初始化调色板
  745. for (int i = 0; i < 256; i++)
  746. {
  747. m_objBitmapInfo.bmiColors[i].rgbBlue = (byte)i;
  748. m_objBitmapInfo.bmiColors[i].rgbGreen = (byte)i;
  749. m_objBitmapInfo.bmiColors[i].rgbRed = (byte)i;
  750. m_objBitmapInfo.bmiColors[i].rgbReserved = 0;
  751. }
  752. }
  753. m_pBitmapInfo = Marshal.AllocHGlobal(2048);
  754. Marshal.StructureToPtr(m_objBitmapInfo, m_pBitmapInfo, false);
  755. }
  756. /// <summary>
  757. /// 释放buffer
  758. /// </summary>
  759. public void ReleaseBuffer()
  760. {
  761. // 释放输出Buffer内存
  762. if (m_pOutBuffer != IntPtr.Zero)
  763. {
  764. Marshal.FreeCoTaskMem(m_pOutBuffer);
  765. m_pOutBuffer = IntPtr.Zero;
  766. }
  767. if (m_pBitmapInfo != IntPtr.Zero)
  768. {
  769. Marshal.FreeHGlobal(m_pBitmapInfo);
  770. m_pBitmapInfo = IntPtr.Zero;
  771. }
  772. }
  773. /// <summary>
  774. /// 是否支持彩色
  775. /// </summary>
  776. /// <param name="bIsColorFilter">是否支持彩色</param>
  777. public void IsSupportColor(ref bool bIsColorFilter)
  778. {
  779. bool bIsImplemented = false;
  780. bool bIsMono = false;
  781. string strPixelFormat = "";
  782. uint nPixelFormatValue = 0;
  783. strPixelFormat = m_objIGXDevice.GetRemoteFeatureControl().GetEnumFeature("PixelFormat").GetValue();
  784. if (0 == string.Compare(strPixelFormat, 0, "Mono", 0, 4))
  785. {
  786. bIsMono = true;
  787. }
  788. else
  789. {
  790. bIsMono = false;
  791. }
  792. // 通过当前像素格式判断是否为彩色相机
  793. CDecide.GetConvertPixelFormat(strPixelFormat, ref nPixelFormatValue);
  794. bIsImplemented = CDecide.GetIsGray(nPixelFormatValue);
  795. if ((!bIsMono) && (!bIsImplemented))
  796. {
  797. bIsColorFilter = true;
  798. }
  799. else
  800. {
  801. bIsColorFilter = false;
  802. }
  803. }
  804. /// <summary>
  805. /// 计算宽度所占的字节数
  806. /// </summary>
  807. /// <param name="nWidth">图像宽度</param>
  808. /// <param name="bIsColor">是否是彩色相机</param>
  809. /// <returns>图像一行所占的字节数</returns>
  810. private int __GetStride(int nWidth, bool bIsColor)
  811. {
  812. return bIsColor ? nWidth * 3 : nWidth;
  813. }
  814. /// <summary>
  815. /// 通过GX_PIXEL_FORMAT_ENTRY获取最优Bit位
  816. /// </summary>
  817. /// <param name="em">图像数据格式</param>
  818. /// <returns>最优Bit位</returns>
  819. public GX_VALID_BIT_LIST GetBestValudBit(GX_PIXEL_FORMAT_ENTRY emPixelFormatEntry)
  820. {
  821. GX_VALID_BIT_LIST emValidBits = GX_VALID_BIT_LIST.GX_BIT_0_7;
  822. switch (emPixelFormatEntry)
  823. {
  824. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO8:
  825. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR8:
  826. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG8:
  827. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB8:
  828. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG8:
  829. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_RGB8:
  830. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BGR8:
  831. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_R8:
  832. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_G8:
  833. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_B8:
  834. {
  835. emValidBits = GX_VALID_BIT_LIST.GX_BIT_0_7;
  836. break;
  837. }
  838. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO10:
  839. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO10_P:
  840. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO10_PACKED:
  841. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR10:
  842. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG10:
  843. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB10:
  844. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG10:
  845. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG10_P:
  846. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG10_PACKED:
  847. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB10_P:
  848. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB10_PACKED:
  849. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR10_P:
  850. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR10_PACKED:
  851. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG10_P:
  852. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG10_PACKED:
  853. {
  854. emValidBits = GX_VALID_BIT_LIST.GX_BIT_2_9;
  855. break;
  856. }
  857. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO12:
  858. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO12_P:
  859. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO12_PACKED:
  860. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR12:
  861. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG12:
  862. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB12:
  863. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG12:
  864. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG12_P:
  865. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG12_PACKED:
  866. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB12_P:
  867. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB12_PACKED:
  868. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR12_P:
  869. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR12_PACKED:
  870. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG12_P:
  871. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG12_PACKED:
  872. {
  873. emValidBits = GX_VALID_BIT_LIST.GX_BIT_4_11;
  874. break;
  875. }
  876. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO14:
  877. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR14:
  878. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG14:
  879. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB14:
  880. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG14:
  881. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG14_P:
  882. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB14_P:
  883. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR14_P:
  884. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG14_P:
  885. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO14_P:
  886. {
  887. emValidBits = GX_VALID_BIT_LIST.GX_BIT_6_13;
  888. break;
  889. }
  890. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO16:
  891. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GR16:
  892. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_RG16:
  893. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_GB16:
  894. case GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_BAYER_BG16:
  895. {
  896. emValidBits = GX_VALID_BIT_LIST.GX_BIT_8_15;
  897. break;
  898. }
  899. default:
  900. break;
  901. }
  902. return emValidBits;
  903. }
  904. /// <summary>
  905. /// 判断PixelFormat是否为8位
  906. /// </summary>
  907. /// <param name="emPixelFormatEntry">图像数据格式</param>
  908. /// <returns>true为8为数据,false为非8位数据</returns>
  909. private bool __IsPixelFormat8(GX_PIXEL_FORMAT_ENTRY emPixelFormatEntry)
  910. {
  911. const uint PIXEL_FORMATE_BIT = 0x00FF0000; //用于与当前的数据格式进行与运算得到当前的数据位数
  912. const uint GX_PIXEL_8BIT = 0x00080000; //8位数据图像格式
  913. bool bIsPixelFormat8 = false;
  914. uint uiPixelFormatEntry = (uint)emPixelFormatEntry;
  915. if ((uiPixelFormatEntry & PIXEL_FORMATE_BIT) == GX_PIXEL_8BIT)
  916. {
  917. bIsPixelFormat8 = true;
  918. }
  919. return bIsPixelFormat8;
  920. }
  921. /// <summary>
  922. /// 转换图片
  923. /// </summary>
  924. /// <param name="nHeight">高</param>
  925. /// <param name="nWidth">宽</param>
  926. /// <param name="pImageBuf">图片数据</param>
  927. /// <param name="enPixelType">像素格式</param>
  928. public ICogImage ConvertImage(UInt32 nWidth, UInt32 nHeight, IntPtr pImageBuf, GX_PIXEL_FORMAT_ENTRY enPixelType)
  929. {
  930. try
  931. {
  932. if (enPixelType == GX_PIXEL_FORMAT_ENTRY.GX_PIXEL_FORMAT_MONO8)
  933. {
  934. CogImage8Root cogImage8Root = new CogImage8Root();
  935. cogImage8Root.Initialize((Int32)nWidth, (Int32)nHeight, pImageBuf, (Int32)nWidth, null);
  936. CogImage8Grey cogImage8Grey = new CogImage8Grey();
  937. cogImage8Grey.SetRoot(cogImage8Root);
  938. var image = cogImage8Grey.ScaleImage((int)nWidth, (int)nHeight);
  939. System.GC.Collect();
  940. return image;
  941. }
  942. else
  943. {
  944. int stride = (int)nWidth * 3;
  945. CogImage24PlanarColor cogImage24PlanarColor = new CogImage24PlanarColor(new Bitmap((int)nWidth, (int)nHeight, stride, PixelFormat.Format24bppRgb, pImageBuf));
  946. var m_InputImageRgb24 = cogImage24PlanarColor.Copy(CogImageCopyModeConstants.CopyPixels);
  947. return m_InputImageRgb24;
  948. }
  949. }
  950. catch (System.Exception)
  951. {
  952. return null;
  953. }
  954. }
  955. #endregion
  956. #region 属性通知
  957. /// <summary>
  958. /// Occurs when a property value changes.
  959. /// </summary>
  960. public event PropertyChangedEventHandler PropertyChanged;
  961. /// <summary>
  962. /// Checks if a property already matches a desired value. Sets the property and
  963. /// notifies listeners only when necessary.
  964. /// </summary>
  965. /// <typeparam name="T">Type of the property.</typeparam>
  966. /// <param name="storage">Reference to a property with both getter and setter.</param>
  967. /// <param name="value">Desired value for the property.</param>
  968. /// <param name="propertyName">Name of the property used to notify listeners. This
  969. /// value is optional and can be provided automatically when invoked from compilers that
  970. /// support CallerMemberName.</param>
  971. /// <returns>True if the value was changed, false if the existing value matched the
  972. /// desired value.</returns>
  973. protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
  974. {
  975. if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
  976. storage = value;
  977. RaisePropertyChanged(propertyName);
  978. return true;
  979. }
  980. /// <summary>
  981. /// Checks if a property already matches a desired value. Sets the property and
  982. /// notifies listeners only when necessary.
  983. /// </summary>
  984. /// <typeparam name="T">Type of the property.</typeparam>
  985. /// <param name="storage">Reference to a property with both getter and setter.</param>
  986. /// <param name="value">Desired value for the property.</param>
  987. /// <param name="propertyName">Name of the property used to notify listeners. This
  988. /// value is optional and can be provided automatically when invoked from compilers that
  989. /// support CallerMemberName.</param>
  990. /// <param name="onChanged">Action that is called after the property value has been changed.</param>
  991. /// <returns>True if the value was changed, false if the existing value matched the
  992. /// desired value.</returns>
  993. protected virtual bool SetProperty<T>(ref T storage, T value, Action onChanged, [CallerMemberName] string propertyName = null)
  994. {
  995. if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
  996. storage = value;
  997. onChanged?.Invoke();
  998. RaisePropertyChanged(propertyName);
  999. return true;
  1000. }
  1001. /// <summary>
  1002. /// Raises this object's PropertyChanged event.
  1003. /// </summary>
  1004. /// <param name="propertyName">Name of the property used to notify listeners. This
  1005. /// value is optional and can be provided automatically when invoked from compilers
  1006. /// that support <see cref="CallerMemberNameAttribute"/>.</param>
  1007. protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
  1008. {
  1009. OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
  1010. }
  1011. /// <summary>
  1012. /// Raises this object's PropertyChanged event.
  1013. /// </summary>
  1014. /// <param name="args">The PropertyChangedEventArgs</param>
  1015. protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
  1016. {
  1017. PropertyChanged?.Invoke(this, args);
  1018. }
  1019. #endregion
  1020. }
  1021. }