GalaxyCamera.cs 39 KB

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