GalaxyCamera.cs 42 KB

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