MVOptCamera.cs 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Diagnostics;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Runtime.CompilerServices;
  8. using System.Runtime.InteropServices;
  9. using System.Text;
  10. using System.Threading;
  11. using System.Threading.Tasks;
  12. using Cognex.VisionPro;
  13. using LampInspectionMachine.Interfaces;
  14. using LampInspectionMachine.Log4xml;
  15. using GdiPlus = System.Drawing.Imaging;
  16. using LampInspectionMachine.Model;
  17. using Microsoft.Win32;
  18. using MvCameraControl;
  19. using SciCamera.Net;
  20. using static System.Windows.Forms.AxHost;
  21. using static SciCamera.Net.SciCam;
  22. using MvCamCtrl.NET;
  23. namespace LampInspectionMachine.Cameralibs.OPTCamera
  24. {
  25. public class MVOptCamera : ICamera, INotifyPropertyChanged
  26. {
  27. #region 字段
  28. private Thread m_hReceiveThread;
  29. #endregion
  30. #region 属性
  31. public CameraBrand CameraBrand { get => CameraBrand.HikRobot_MVS; }
  32. public string Name { get; private set; }
  33. public Guid ID { get; private set; }
  34. public string ManufacturerName { get; private set; }
  35. public string ModelName { get; private set; }
  36. public string SerialNumber { get; private set; }
  37. public CameraType CameraType { get; private set; }
  38. public SCI_DEVICE_INFO CameraInfo;
  39. public SciCam.SCI_DEVICE_INFO_LIST m_stDevList = new SciCam.SCI_DEVICE_INFO_LIST(); //ch:设备列表 | en:Device List
  40. public SciCam m_currentDev = new SciCam();
  41. public UInt32 ImageWidth { get; private set; }
  42. public UInt32 ImageHeight { get; private set; }
  43. public MvGvspPixelType PixelType { get; private set; }
  44. private bool _IsGrabbing;
  45. /// <summary>
  46. /// 正在采集
  47. /// </summary>
  48. public bool IsGrabbing
  49. {
  50. get { return _IsGrabbing; }
  51. private set { SetProperty(ref _IsGrabbing, value); }
  52. }
  53. private ICogImage _Image;
  54. public ICogImage Image
  55. {
  56. get { return _Image; }
  57. private set { SetProperty(ref _Image, value); }
  58. }
  59. public bool IsConnected { get; private set; }
  60. private bool IsHaveCamera = false;
  61. /// <summary>
  62. /// 采集用时
  63. /// </summary>
  64. public TimeSpan TotalTime { get; private set; }
  65. /// <summary>
  66. /// 错误信息
  67. /// </summary>
  68. public string ErrorMessage { get; private set; }
  69. #endregion
  70. #region 事件
  71. /// <summary>
  72. /// 手动采集图像回调事件
  73. /// </summary>
  74. public event Action<ICogImage, TimeSpan, string> ImageCallbackEvent;
  75. /// <summary>
  76. /// 触发取图回调事件
  77. /// </summary>
  78. public event Action<ICogImage> GrabImageCallbackEvent;
  79. public event Action<Guid, bool> CameraConnectChangedEvent;
  80. #endregion
  81. public MVOptCamera(Guid _ID, string _Name, string _SerialNumber)
  82. {
  83. ID = _ID;
  84. Name = _Name;
  85. SerialNumber = _SerialNumber;
  86. uint nReVal = SciCam.DiscoveryDevices(ref m_stDevList, (uint)(SciCam.SciCamTLType.SciCam_TLType_Gige) | (uint)(SciCam.SciCamTLType.SciCam_TLType_Usb3));
  87. if (nReVal != SciCam.SCI_CAMERA_OK)
  88. {
  89. throw new Exception("Discovery devices failed!");
  90. }
  91. if (m_stDevList.count == 0)
  92. {
  93. throw new Exception("Discovery devices Success, but found 0 device.");
  94. }
  95. string chDeviceName;
  96. IsHaveCamera = false;
  97. foreach (var devInfo in m_stDevList.pDevInfo)
  98. {
  99. SciCam.SCI_DEVICE_INFO device = devInfo;
  100. SciCam.SciCamTLType devTlType = device.tlType;
  101. SciCam.SciCamDeviceType devType = device.devType;
  102. if (devTlType == SciCam.SciCamTLType.SciCam_TLType_Usb3)
  103. {
  104. SciCam.SCI_DEVICE_USB3_INFO usbinfo = (SciCam.SCI_DEVICE_USB3_INFO)SciCam.ByteToStruct(device.info.usb3Info, typeof(SciCam.SCI_DEVICE_USB3_INFO));
  105. if (!string.IsNullOrEmpty(usbinfo.userDefineName))
  106. {
  107. chDeviceName = string.Format("{0} [{1}]", usbinfo.modelName, usbinfo.userDefineName);
  108. }
  109. else
  110. {
  111. chDeviceName = string.Format("{0} [{1}]", usbinfo.modelName, usbinfo.serialNumber);
  112. }
  113. if (string.Equals(usbinfo.serialNumber, _SerialNumber))
  114. {
  115. ManufacturerName = usbinfo.manufactureName;
  116. ModelName = usbinfo.modelName;
  117. SerialNumber = usbinfo.serialNumber;
  118. CameraType = CameraType.USB;
  119. CameraInfo = device;
  120. IsHaveCamera = true;
  121. break;
  122. }
  123. }
  124. }
  125. }
  126. #region 方法
  127. /// <summary>
  128. /// 获取设备
  129. /// </summary>
  130. /// <returns></returns>
  131. public static CameraInfo[] GetDevices()
  132. {
  133. List<CameraInfo> cameras = new List<CameraInfo>();
  134. try
  135. {
  136. // ch: 初始化 SDK | en: Initialize SDK
  137. SDKSystem.Initialize();
  138. List<IDeviceInfo> devInfoList = new List<IDeviceInfo>();
  139. // ch:枚举设备 | en:Enum device
  140. int nRet = DeviceEnumerator.EnumDevices(DeviceTLayerType.MvGigEDevice | DeviceTLayerType.MvVirGigEDevice | DeviceTLayerType.MvGenTLGigEDevice | DeviceTLayerType.MvUsbDevice | DeviceTLayerType.MvVirUsbDevice, out devInfoList);
  141. if (nRet != MvError.MV_OK)
  142. {
  143. throw new Exception($"Enumerate devices fail: {nRet:x8}");
  144. }
  145. foreach (var devInfo in devInfoList)
  146. {
  147. if (devInfo.TLayerType == DeviceTLayerType.MvGigEDevice || devInfo.TLayerType == DeviceTLayerType.MvVirGigEDevice || devInfo.TLayerType == DeviceTLayerType.MvGenTLGigEDevice)
  148. {
  149. IGigEDeviceInfo gigeDevInfo = devInfo as IGigEDeviceInfo;
  150. uint nIp1 = ((gigeDevInfo.CurrentIp & 0xff000000) >> 24);
  151. uint nIp2 = ((gigeDevInfo.CurrentIp & 0x00ff0000) >> 16);
  152. uint nIp3 = ((gigeDevInfo.CurrentIp & 0x0000ff00) >> 8);
  153. uint nIp4 = (gigeDevInfo.CurrentIp & 0x000000ff);
  154. Console.WriteLine("DevIP: {0}.{1}.{2}.{3}", nIp1, nIp2, nIp3, nIp4);
  155. cameras.Add(new CameraInfo()
  156. {
  157. CameraName = "",
  158. CameraBrand = CameraBrand.HikRobot_MVS,
  159. CameraType = CameraType.GIGE,
  160. Id = Guid.NewGuid(),
  161. ManufacturerName = devInfo.ManufacturerName,
  162. Model = devInfo.ModelName,
  163. SerialNumber = devInfo.SerialNumber,
  164. CameraIp = $"{nIp1}.{nIp2}.{nIp3}.{nIp4}",
  165. });
  166. }
  167. else if (devInfo.TLayerType == DeviceTLayerType.MvUsbDevice || devInfo.TLayerType == DeviceTLayerType.MvVirUsbDevice)
  168. {
  169. cameras.Add(new CameraInfo()
  170. {
  171. CameraName = "",
  172. CameraBrand = CameraBrand.HikRobot_MVS,
  173. CameraType = CameraType.USB,
  174. Id = Guid.NewGuid(),
  175. ManufacturerName = devInfo.ManufacturerName,
  176. Model = devInfo.ModelName,
  177. SerialNumber = devInfo.SerialNumber,
  178. CameraIp = "",
  179. });
  180. }
  181. }
  182. }
  183. catch (Exception ex)
  184. {
  185. // LogHelper.WriteLogError("搜索海康相机列表时出错!", ex);
  186. }
  187. return cameras.ToArray();
  188. }
  189. /// <summary>
  190. /// 打开相机
  191. /// </summary>
  192. /// <returns></returns>
  193. /// <exception cref="Exception"></exception>
  194. public bool OpenDevice()
  195. {
  196. if (!IsHaveCamera)
  197. {
  198. SCI_DEVICE_INFO_LIST devInfoList = new SCI_DEVICE_INFO_LIST();
  199. // ch:枚举设备 | en:Enum device
  200. uint nReVal = SciCam.DiscoveryDevices(ref devInfoList, (uint)(SciCam.SciCamTLType.SciCam_TLType_Gige) | (uint)(SciCam.SciCamTLType.SciCam_TLType_Usb3));
  201. if (nReVal != SciCam.SCI_CAMERA_OK)
  202. {
  203. throw new Exception("Discovery devices failed!");
  204. }
  205. string chDeviceName;
  206. foreach (var devInfo in devInfoList.pDevInfo)
  207. {
  208. SciCam.SCI_DEVICE_INFO device = devInfo;
  209. SciCam.SciCamTLType devTlType = device.tlType;
  210. SciCam.SciCamDeviceType devType = device.devType;
  211. if (devTlType == SciCam.SciCamTLType.SciCam_TLType_Usb3)
  212. {
  213. SciCam.SCI_DEVICE_USB3_INFO usbinfo = (SciCam.SCI_DEVICE_USB3_INFO)SciCam.ByteToStruct(device.info.usb3Info, typeof(SciCam.SCI_DEVICE_USB3_INFO));
  214. if (!string.IsNullOrEmpty(usbinfo.userDefineName))
  215. {
  216. chDeviceName = string.Format("{0} [{1}]", usbinfo.modelName, usbinfo.userDefineName);
  217. }
  218. else
  219. {
  220. chDeviceName = string.Format("{0} [{1}]", usbinfo.modelName, usbinfo.serialNumber);
  221. }
  222. if (string.Equals(usbinfo.serialNumber, SerialNumber))
  223. {
  224. ManufacturerName = usbinfo.manufactureName;
  225. ModelName = usbinfo.modelName;
  226. SerialNumber = usbinfo.serialNumber;
  227. CameraType = CameraType.GIGE;
  228. CameraInfo = device;
  229. IsHaveCamera = true;
  230. break;
  231. }
  232. }
  233. }
  234. IsConnected = false;
  235. if (!IsHaveCamera)
  236. {
  237. throw new Exception("没有发现相机");
  238. }
  239. }
  240. if (!IsConnected)
  241. {
  242. uint nReVal = SciCam.SCI_CAMERA_OK;
  243. for (int i = 0; i < m_stDevList.count; i++)
  244. {
  245. SciCam.SCI_DEVICE_USB3_INFO usbinfo = (SciCam.SCI_DEVICE_USB3_INFO)SciCam.ByteToStruct(m_stDevList.pDevInfo[i].info.usb3Info, typeof(SciCam.SCI_DEVICE_USB3_INFO));
  246. if (SerialNumber == usbinfo.serialNumber)
  247. {
  248. nReVal = m_currentDev.CreateDevice(ref m_stDevList.pDevInfo[i]);
  249. if (nReVal == SciCam.SCI_CAMERA_OK)
  250. {
  251. nReVal = m_currentDev.OpenDevice();
  252. if (nReVal != SciCam.SCI_CAMERA_OK)
  253. {
  254. IsConnected = false;
  255. m_currentDev.DeleteDevice();
  256. LogHelper.Info("Open device failed"+ nReVal);
  257. return false;
  258. }
  259. IsConnected = true;
  260. break;
  261. }
  262. else
  263. {
  264. IsConnected = false;
  265. }
  266. }
  267. }
  268. }
  269. return IsConnected;
  270. }
  271. /// <summary>
  272. /// 关闭相机
  273. /// </summary>
  274. public void CloseDevice()
  275. {
  276. if (IsGrabbing)
  277. {
  278. StopGrabbing();
  279. }
  280. if (!IsConnected) return;
  281. uint nReVal = m_currentDev.CloseDevice();
  282. if (nReVal != SciCam.SCI_CAMERA_OK)
  283. {
  284. LogHelper.Info("Close device failed");
  285. return;
  286. }
  287. nReVal = m_currentDev.DeleteDevice();
  288. if (nReVal != SciCam.SCI_CAMERA_OK)
  289. {
  290. LogHelper.Info("Delete device failed" + nReVal);
  291. }
  292. IsGrabbing = false;
  293. if (IsConnected)
  294. {
  295. IsConnected = false;
  296. CameraConnectChangedEvent?.Invoke(ID, IsConnected);
  297. }
  298. }
  299. /// <summary>
  300. /// 取图前的必要操作步骤
  301. /// </summary>
  302. /// <returns></returns>
  303. //private Int32 NecessaryOperBeforeGrab()
  304. //{
  305. // // ch:取图像宽 | en:Get Iamge Width
  306. // IIntValue pcWidth = null;
  307. // int nRet = m_MyCamera.Parameters.GetIntValue("Width", out pcWidth);
  308. // if (nRet != MvError.MV_OK)
  309. // {
  310. // return nRet;
  311. // }
  312. // ImageWidth = (UInt32)pcWidth.CurValue;
  313. // // ch:取图像高 | en:Get Iamge Height
  314. // IIntValue pcHeight = null;
  315. // nRet = m_MyCamera.Parameters.GetIntValue("Height", out pcHeight);
  316. // if (nRet != MvError.MV_OK)
  317. // {
  318. // return nRet;
  319. // }
  320. // ImageHeight = (UInt32)pcHeight.CurValue;
  321. // // ch:取像素格式 | en:Get Pixel Format
  322. // IEnumValue pcPixelFormat = null;
  323. // nRet = m_MyCamera.Parameters.GetEnumValue("PixelFormat", out pcPixelFormat);
  324. // if (nRet != MvError.MV_OK)
  325. // {
  326. // return nRet;
  327. // }
  328. // PixelType = (MvCameraControl.MvGvspPixelType)pcPixelFormat.CurEnumEntry.Value;
  329. // return MvError.MV_OK;
  330. //}
  331. /// <summary>
  332. /// 采集图像
  333. /// </summary>
  334. /// <returns></returns>
  335. public ICogImage Grab()
  336. {
  337. m_currentDev.StartGrabbing();
  338. uint nReVal = SciCam.SCI_CAMERA_OK;
  339. IntPtr payload = IntPtr.Zero;
  340. nReVal = m_currentDev.Grab(ref payload);
  341. if (nReVal == SciCam.SCI_CAMERA_OK)
  342. {
  343. int reVal = GetConvertedInfo(payload);
  344. }
  345. m_currentDev.StopGrabbing();
  346. return Image;
  347. }
  348. /// <summary>
  349. /// 开始采集图像
  350. /// </summary>
  351. public void StartGrabbing()
  352. {
  353. if (IsGrabbing)
  354. return;
  355. IsGrabbing = true;
  356. m_hReceiveThread = new Thread(GetStreamThreadProc) { IsBackground = true };
  357. m_hReceiveThread.Start();
  358. }
  359. /// <summary>
  360. /// 开始触发模式采集图像
  361. /// </summary>
  362. public void StartTriggerGrabbing()
  363. {
  364. StartGrabbing();
  365. }
  366. /// <summary>
  367. /// 停止采集图像
  368. /// </summary>
  369. public void StopGrabbing()
  370. {
  371. try
  372. {
  373. if (IsGrabbing)
  374. {
  375. IsGrabbing = false;
  376. Thread.Sleep(1000);
  377. }
  378. if (m_hReceiveThread != null)
  379. {
  380. m_hReceiveThread.Abort();
  381. m_hReceiveThread = null;
  382. }
  383. }
  384. catch (Exception)
  385. {
  386. }
  387. }
  388. //private void FrameGrabedEventHandler(object sender, FrameGrabbedEventArgs e)
  389. //{
  390. // GrabImageCallbackEvent?.Invoke(AnalyticImage(e.FrameOut));
  391. // //Console.WriteLine("Get one frame: Width[{0}] , Height[{1}] , ImageSize[{2}], FrameNum[{3}]", e.FrameOut.Image.Width, e.FrameOut.Image.Height, e.FrameOut.Image.ImageSize, e.FrameOut.FrameNum);
  392. //}
  393. /// <summary>
  394. /// Converts the image data from the specified <see cref="IFrameOut"/> object into an <see cref="ICogImage"/>
  395. /// format.
  396. /// </summary>
  397. /// <remarks>This method processes both color and monochrome images, converting them to a
  398. /// compatible format for further analysis. Unsupported pixel formats are not processed, and the method will
  399. /// return <see langword="null"/> in such cases. The caller is responsible for ensuring that the <paramref
  400. /// name="frameOut"/> parameter is valid and properly initialized.</remarks>
  401. /// <param name="frameOut">The frame output containing the image data to be analyzed and converted.</param>
  402. /// <returns>An <see cref="ICogImage"/> object representing the converted image. Returns <see langword="null"/> if the
  403. /// image format is unsupported or if an error occurs during conversion.</returns>
  404. /// <summary>
  405. /// 设置曝光时间
  406. /// </summary>
  407. /// <param name="ExposureTime"></param>
  408. /// <returns></returns>
  409. public bool SetExposureTime(float ExposureTime)
  410. {
  411. string[] nodeName = new string[]
  412. {
  413. "ExposureTime",
  414. "ExposureTimeAbs",
  415. "ExposureTimeRaw"
  416. };
  417. uint nReVal = SciCam.SCI_CAMERA_OK;
  418. int iExposure = (int)ExposureTime;
  419. for (int i = 0; i < nodeName.Count(); i++)
  420. {
  421. nReVal = m_currentDev.SetIntValue(nodeName[i], iExposure);
  422. if (nReVal != SciCam.SCI_CAMERA_OK)
  423. {
  424. double dExposure = ExposureTime;
  425. nReVal = m_currentDev.SetFloatValue(nodeName[i], dExposure);
  426. if (nReVal == SciCam.SCI_CAMERA_OK)
  427. {
  428. return true;
  429. }
  430. }
  431. }
  432. return false;
  433. }
  434. /// <summary>
  435. /// 获取曝光时间
  436. /// </summary>
  437. /// <returns></returns>
  438. public float GetExposureTime()
  439. {
  440. string[] nodeName = new string[]
  441. {
  442. "ExposureTime",
  443. "ExposureTimeAbs",
  444. "ExposureTimeRaw"
  445. };
  446. uint nReVal = SciCam.SCI_CAMERA_OK;
  447. for (int i = 0; i < nodeName.Count(); i++)
  448. {
  449. SciCam.SCI_NODE_VAL_INT iNodeVal = new SciCam.SCI_NODE_VAL_INT();
  450. nReVal = m_currentDev.GetIntValueEx(SciCam.SciCamDeviceXmlType.SciCam_DeviceXml_Camera, nodeName[i], ref iNodeVal);
  451. if (nReVal != SciCam.SCI_CAMERA_OK)
  452. {
  453. SciCam.SCI_NODE_VAL_FLOAT fNodeVal = new SciCam.SCI_NODE_VAL_FLOAT();
  454. nReVal = m_currentDev.GetFloatValueEx(SciCam.SciCamDeviceXmlType.SciCam_DeviceXml_Camera, nodeName[i], ref fNodeVal);
  455. if (nReVal == SciCam.SCI_CAMERA_OK)
  456. {
  457. return (float)fNodeVal.dVal;
  458. }
  459. }
  460. else
  461. {
  462. return iNodeVal.nVal;
  463. }
  464. }
  465. return 0;
  466. }
  467. /// <summary>
  468. /// 设置增益
  469. /// </summary>
  470. /// <param name="Gain"></param>
  471. /// <returns></returns>
  472. public bool SetGain(float Gain)
  473. {
  474. uint nReVal = m_currentDev.SetFloatValue("Gain", Gain);
  475. if (nReVal != SciCam.SCI_CAMERA_OK)
  476. {
  477. return false;
  478. }
  479. else
  480. {
  481. return true;
  482. }
  483. }
  484. /// <summary>
  485. /// 获取增益
  486. /// </summary>
  487. /// <returns></returns>
  488. public float GetGain()
  489. {
  490. SciCam.SCI_NODE_VAL_FLOAT fNodeVal = new SciCam.SCI_NODE_VAL_FLOAT();
  491. uint nReVal = m_currentDev.GetFloatValueEx(SciCam.SciCamDeviceXmlType.SciCam_DeviceXml_Camera, "Gain", ref fNodeVal);
  492. if (nReVal == SciCam.SCI_CAMERA_OK)
  493. {
  494. return (float)fNodeVal.dVal;
  495. }
  496. return 0;
  497. }
  498. /// <summary>
  499. /// ch:获取触发模式 | en:Get Trigger Mode
  500. /// </summary>
  501. /// <returns>On/Off</returns>
  502. public bool GetTriggerMode()
  503. {
  504. SciCam.SCI_NODE_VAL_ENUM eNodeVal = new SciCam.SCI_NODE_VAL_ENUM();
  505. uint nReVal = m_currentDev.GetEnumValue("TriggerMode", ref eNodeVal);
  506. if (nReVal != SciCam.SCI_CAMERA_OK)
  507. {
  508. return false ;
  509. }
  510. return true;
  511. }
  512. /// <summary>
  513. /// 设置触发模式
  514. /// </summary>
  515. /// <param name="mode">触发模式</param>
  516. /// <param name="triggerSource">触发源0 - Line0;1 - Line1;2 - Line2;3 - Line3;4 - Counter;7 - Software;</param>
  517. /// <returns></returns>
  518. public bool SetTriggerMode(bool mode, int triggerSource)
  519. {
  520. string strmode = mode ? "On" : "Off";
  521. if (m_currentDev.IsDeviceOpen())
  522. {
  523. uint nRet = m_currentDev.SetEnumValueByStringEx(SciCam.SciCamDeviceXmlType.SciCam_DeviceXml_Camera, "TriggerMode", strmode);
  524. if (nRet != MvError.MV_OK)
  525. {
  526. return false;
  527. }
  528. if (mode)
  529. {
  530. return SetTriggerSource(triggerSource);
  531. }
  532. else
  533. {
  534. }
  535. return true;
  536. }
  537. return false;
  538. }
  539. /// <summary>
  540. /// Sets the trigger source for the camera.
  541. /// </summary>
  542. /// <param name="source">0 - Line0;1 - Line1;2 - Line2;3 - Line3;4 - Counter;7 - Software;</param>
  543. /// <returns></returns>
  544. /// <exception cref="ArgumentOutOfRangeException"></exception>
  545. public bool SetTriggerSource(int source)
  546. {
  547. // ch:触发源选择:0 - Line0; | en:Trigger source select:0 - Line0;
  548. // 1 - Line1;
  549. // 2 - Line2;
  550. // 3 - Line3;
  551. // 4 - Counter;
  552. // 7 - Software;
  553. string sourceStr;
  554. switch (source)
  555. {
  556. case 0: sourceStr = "Line1"; break;
  557. case 1: sourceStr = "Line1"; break;
  558. case 2: sourceStr = "Line2"; break;
  559. case 3: sourceStr = "Line3"; break;
  560. case 4: sourceStr = "Counter"; break;
  561. case 7: sourceStr = "Software"; break;
  562. default: throw new ArgumentOutOfRangeException(nameof(source), "Invalid trigger source value");
  563. }
  564. uint nReVal = m_currentDev.SetEnumValueByStringEx(SciCam.SciCamDeviceXmlType.SciCam_DeviceXml_Camera, "TriggerSource", "Line1");
  565. if (SciCam.SCI_CAMERA_OK != nReVal)
  566. {
  567. LogHelper.Info("Set TriggerSource to Line1 fail! ");
  568. return false;
  569. }
  570. return true;
  571. }
  572. /// <summary>
  573. /// Retrieves the current trigger source setting of the camera.
  574. /// </summary>
  575. /// <remarks>This method queries the camera's parameters to determine the current trigger source.
  576. /// If the retrieval is unsuccessful or the trigger source is not recognized, the method returns -1.</remarks>
  577. /// <returns>An integer representing the trigger source: <list type="bullet"> <item><description>0 for
  578. /// "Line0".</description></item> <item><description>1 for "Line1".</description></item> <item><description>2
  579. /// for "Line2".</description></item> <item><description>3 for "Line3".</description></item>
  580. /// <item><description>4 for "Counter".</description></item> <item><description>7 for
  581. /// "Software".</description></item> <item><description>-1 if the trigger source is unknown or if the retrieval
  582. /// fails.</description></item> </list></returns>
  583. public int GetTriggerSource()
  584. {
  585. SciCam.SCI_NODE_VAL_ENUM enumValue = new SciCam.SCI_NODE_VAL_ENUM();
  586. uint result = m_currentDev.GetEnumValueEx(SciCam.SciCamDeviceXmlType.SciCam_DeviceXml_Card, "TriggerSource", ref enumValue);
  587. if (result == MvError.MV_OK)
  588. {
  589. switch (enumValue.items[0].desc)
  590. {
  591. case "Line0": return 0;
  592. case "Line1": return 1;
  593. case "Line2": return 2;
  594. case "Line3": return 3;
  595. case "Counter": return 4;
  596. case "Software": return 7;
  597. default: return -1; // 未知触发源
  598. }
  599. }
  600. return -1; // 获取失败
  601. }
  602. /// <summary>
  603. /// Sends a software trigger command to the camera.
  604. /// </summary>
  605. /// <remarks>This method triggers the camera to capture an image or perform an action based on
  606. /// its current configuration. Ensure the camera is properly initialized and configured to respond to software
  607. /// triggers before calling this method.</remarks>
  608. public void TriggerSoftware()
  609. {
  610. // ch:触发软件 | en:Trigger Software
  611. // 执行
  612. uint nReVal = m_currentDev.SetCommandValue("TriggerSoftware");
  613. if (nReVal != SciCam.SCI_CAMERA_OK)
  614. {
  615. LogHelper.Info("TriggerSoftware写入失败");
  616. }
  617. }
  618. private void GetStreamThreadProc()
  619. {
  620. m_currentDev.StartGrabbing();
  621. uint nReVal = SciCam.SCI_CAMERA_OK;
  622. IntPtr payload = IntPtr.Zero;
  623. if (m_currentDev.IsDeviceOpen())
  624. {
  625. while (IsGrabbing)
  626. {
  627. nReVal = m_currentDev.Grab(ref payload);
  628. if (nReVal == SciCam.SCI_CAMERA_OK)
  629. {
  630. int reVal = GetConvertedInfo(payload);
  631. }
  632. nReVal = m_currentDev.FreePayload(payload);
  633. }
  634. }
  635. IsGrabbing = false;
  636. }
  637. private int GetConvertedInfo(IntPtr payload)
  638. {
  639. if (payload == IntPtr.Zero)
  640. {
  641. return -1;
  642. }
  643. SciCam.SCI_CAM_PAYLOAD_ATTRIBUTE payloadAttribute = new SciCam.SCI_CAM_PAYLOAD_ATTRIBUTE();
  644. uint nReVal = SciCam.PayloadGetAttribute(payload, ref payloadAttribute);
  645. if (nReVal != SciCam.SCI_CAMERA_OK)
  646. {
  647. return -1;
  648. }
  649. bool imgIsComplete = payloadAttribute.isComplete;
  650. SciCam.SciCamPayloadMode payloadMode = payloadAttribute.payloadMode;
  651. SciCam.SciCamPixelType imgPixelType = payloadAttribute.imgAttr.pixelType;
  652. ulong imgWidth = payloadAttribute.imgAttr.width;
  653. ulong imgHeight = payloadAttribute.imgAttr.height;
  654. ulong framID = payloadAttribute.frameID;
  655. if (!imgIsComplete || payloadMode != SciCam.SciCamPayloadMode.SciCam_PayloadMode_2D)
  656. {
  657. return -1;
  658. }
  659. IntPtr imgData = IntPtr.Zero;
  660. nReVal = SciCam.PayloadGetImage(payload, ref imgData);
  661. if (nReVal != SciCam.SCI_CAMERA_OK)
  662. {
  663. return -1;
  664. }
  665. long destImgSize = 0;
  666. if (imgPixelType == SciCam.SciCamPixelType.Mono1p ||
  667. imgPixelType == SciCam.SciCamPixelType.Mono2p ||
  668. imgPixelType == SciCam.SciCamPixelType.Mono4p ||
  669. imgPixelType == SciCam.SciCamPixelType.Mono8s ||
  670. imgPixelType == SciCam.SciCamPixelType.Mono8 ||
  671. imgPixelType == SciCam.SciCamPixelType.Mono10 ||
  672. imgPixelType == SciCam.SciCamPixelType.Mono10p ||
  673. imgPixelType == SciCam.SciCamPixelType.Mono12 ||
  674. imgPixelType == SciCam.SciCamPixelType.Mono12p ||
  675. imgPixelType == SciCam.SciCamPixelType.Mono14 ||
  676. imgPixelType == SciCam.SciCamPixelType.Mono16 ||
  677. imgPixelType == SciCam.SciCamPixelType.Mono10Packed ||
  678. imgPixelType == SciCam.SciCamPixelType.Mono12Packed ||
  679. imgPixelType == SciCam.SciCamPixelType.Mono14p)
  680. {
  681. nReVal = SciCam.PayloadConvertImageEx(ref payloadAttribute.imgAttr, imgData, SciCam.SciCamPixelType.Mono8, IntPtr.Zero, ref destImgSize, true, 0);
  682. if (nReVal == SciCam.SCI_CAMERA_OK)
  683. {
  684. IntPtr destImg = Marshal.AllocHGlobal((int)destImgSize);
  685. try
  686. {
  687. nReVal = SciCam.PayloadConvertImageEx(ref payloadAttribute.imgAttr, imgData, SciCam.SciCamPixelType.Mono8, destImg, ref destImgSize, true, 0);
  688. if (nReVal == SciCam.SCI_CAMERA_OK)
  689. {
  690. byte[] bBitmap = new byte[destImgSize];
  691. Marshal.Copy(destImg, bBitmap, 0, (int)destImgSize);
  692. Bitmap bitMap = new Bitmap((int)imgWidth, (int)imgHeight, GdiPlus.PixelFormat.Format8bppIndexed);
  693. GdiPlus.BitmapData bitmapData = bitMap.LockBits(new Rectangle(0, 0, (int)imgWidth, (int)imgHeight), GdiPlus.ImageLockMode.WriteOnly, GdiPlus.PixelFormat.Format8bppIndexed);
  694. Marshal.Copy(bBitmap, 0, bitmapData.Scan0, (int)destImgSize);
  695. bitMap.UnlockBits(bitmapData);
  696. //设置调色板
  697. GdiPlus.ColorPalette palette = bitMap.Palette;
  698. for (int i = 0; i < 256; i++)
  699. {
  700. palette.Entries[i] = Color.FromArgb(i, i, i);
  701. }
  702. bitMap.Palette = palette;
  703. //显示图片
  704. Image = new CogImage8Grey(bitMap);
  705. ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage);
  706. GrabImageCallbackEvent?.Invoke(Image);
  707. }
  708. }
  709. catch (Exception ex)
  710. {
  711. }
  712. finally
  713. {
  714. Marshal.FreeHGlobal(destImg);
  715. }
  716. }
  717. }
  718. else
  719. {
  720. nReVal = SciCam.PayloadConvertImageEx(ref payloadAttribute.imgAttr, imgData, SciCam.SciCamPixelType.RGB8, IntPtr.Zero, ref destImgSize, true, 0);
  721. if (nReVal == SciCam.SCI_CAMERA_OK)
  722. {
  723. IntPtr destImg = Marshal.AllocHGlobal((int)destImgSize);
  724. try
  725. {
  726. nReVal = SciCam.PayloadConvertImageEx(ref payloadAttribute.imgAttr, imgData, SciCam.SciCamPixelType.RGB8, destImg, ref destImgSize, true, 0);
  727. if (nReVal == SciCam.SCI_CAMERA_OK)
  728. {
  729. byte[] bBitmap = new byte[destImgSize];
  730. Marshal.Copy(destImg, bBitmap, 0, (int)destImgSize);
  731. Bitmap bitMap = new Bitmap((int)imgWidth, (int)imgHeight, GdiPlus.PixelFormat.Format24bppRgb);
  732. GdiPlus.BitmapData bitmapData = bitMap.LockBits(new Rectangle(0, 0, (int)imgWidth, (int)imgHeight), GdiPlus.ImageLockMode.WriteOnly, GdiPlus.PixelFormat.Format24bppRgb);
  733. Marshal.Copy(bBitmap, 0, bitmapData.Scan0, (int)destImgSize);
  734. bitMap.UnlockBits(bitmapData);
  735. //显示图片
  736. Image = new CogImage8Grey(bitMap);
  737. ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage);
  738. GrabImageCallbackEvent?.Invoke(Image);
  739. }
  740. }
  741. catch (Exception ex)
  742. {
  743. }
  744. finally
  745. {
  746. Marshal.FreeHGlobal(destImg);
  747. }
  748. }
  749. }
  750. return 0;
  751. }
  752. /// <summary>
  753. /// Converts raw image data into an <see cref="ICogImage"/> object, supporting both monochrome and color pixel
  754. /// formats.
  755. /// </summary>
  756. /// <remarks>This method supports both monochrome (PixelType_Gvsp_Mono8) and color pixel formats.
  757. /// For color images, the method processes the image data as a planar color format.</remarks>
  758. /// <param name="nHeight">The height of the image in pixels.</param>
  759. /// <param name="nWidth">The width of the image in pixels.</param>
  760. /// <param name="pImageBuf">A pointer to the buffer containing the raw image data.</param>
  761. /// <param name="enPixelType">The pixel format of the image, specified as a <see cref="MvCameraControl.MvGvspPixelType"/> value.</param>
  762. /// <returns>An <see cref="ICogImage"/> object representing the converted image. Returns <see langword="null"/> if the
  763. /// conversion fails.</returns>
  764. private ICogImage ConvertToICogImage(UInt32 nHeight, UInt32 nWidth, IntPtr pImageBuf, MvCameraControl.MvGvspPixelType enPixelType)
  765. {
  766. ICogImage cogImage = null;
  767. // ch:获取步长 || en: Get nRowStep
  768. uint m_nRowStep = nWidth * nHeight;
  769. // ch: 显示 || display
  770. try
  771. {
  772. if (enPixelType == MvCameraControl.MvGvspPixelType.PixelType_Gvsp_Mono8)
  773. {
  774. CogImage8Root cogImage8Root = new CogImage8Root();
  775. cogImage8Root.Initialize((Int32)nWidth, (Int32)nHeight, pImageBuf, (Int32)nWidth, null);
  776. CogImage8Grey cogImage8Grey = new CogImage8Grey();
  777. cogImage8Grey.SetRoot(cogImage8Root);
  778. cogImage = cogImage8Grey.ScaleImage((int)nWidth, (int)nHeight);
  779. System.GC.Collect();
  780. }
  781. else
  782. {
  783. CogImage8Root image0 = new CogImage8Root();
  784. IntPtr ptr0 = new IntPtr(pImageBuf.ToInt64());
  785. image0.Initialize((int)nWidth, (int)nHeight, ptr0, (int)nWidth, null);
  786. CogImage8Root image1 = new CogImage8Root();
  787. IntPtr ptr1 = new IntPtr(pImageBuf.ToInt64() + m_nRowStep);
  788. image1.Initialize((int)nWidth, (int)nHeight, ptr1, (int)nWidth, null);
  789. CogImage8Root image2 = new CogImage8Root();
  790. IntPtr ptr2 = new IntPtr(pImageBuf.ToInt64() + m_nRowStep * 2);
  791. image2.Initialize((int)nWidth, (int)nHeight, ptr2, (int)nWidth, null);
  792. CogImage24PlanarColor colorImage = new CogImage24PlanarColor();
  793. colorImage.SetRoots(image0, image1, image2);
  794. cogImage = colorImage.ScaleImage((int)nWidth, (int)nHeight);
  795. System.GC.Collect();
  796. }
  797. }
  798. catch (System.Exception ex)
  799. {
  800. ErrorMessage = $"转换ICogImage出错: {ex.Message}";
  801. return null;
  802. }
  803. return cogImage;
  804. }
  805. /// <summary>
  806. /// 图像是否为Mono格式
  807. /// </summary>
  808. /// <param name="enType"></param>
  809. /// <returns></returns>
  810. private bool IsMonoPixelFormat(MvCameraControl.MvGvspPixelType enType)
  811. {
  812. switch (enType)
  813. {
  814. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_Mono8:
  815. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_Mono10:
  816. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_Mono10_Packed:
  817. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_Mono12:
  818. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_Mono12_Packed:
  819. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_Mono16:
  820. return true;
  821. default:
  822. return false;
  823. }
  824. }
  825. /// <summary>
  826. /// 图像是否为彩色
  827. /// </summary>
  828. /// <param name="enType"></param>
  829. /// <returns></returns>
  830. private bool IsColorPixelFormat(MvCameraControl.MvGvspPixelType enType)
  831. {
  832. switch (enType)
  833. {
  834. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_RGB8_Packed:
  835. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BGR8_Packed:
  836. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_RGBA8_Packed:
  837. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BGRA8_Packed:
  838. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_YUV422_Packed:
  839. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_YUV422_YUYV_Packed:
  840. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGR8:
  841. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerRG8:
  842. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGB8:
  843. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerBG8:
  844. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerRBGG8:
  845. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGB10:
  846. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGB10_Packed:
  847. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerBG10:
  848. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerBG10_Packed:
  849. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerRG10:
  850. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerRG10_Packed:
  851. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGR10:
  852. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGR10_Packed:
  853. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGB12:
  854. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGB12_Packed:
  855. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerBG12:
  856. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerBG12_Packed:
  857. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerRG12:
  858. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerRG12_Packed:
  859. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGR12:
  860. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGR12_Packed:
  861. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGR16:
  862. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerRG16:
  863. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerGB16:
  864. case MvCameraControl.MvGvspPixelType.PixelType_Gvsp_BayerBG16:
  865. return true;
  866. default:
  867. return false;
  868. }
  869. }
  870. #endregion
  871. #region 属性通知
  872. /// <summary>
  873. /// Occurs when a property value changes.
  874. /// </summary>
  875. public event PropertyChangedEventHandler PropertyChanged;
  876. /// <summary>
  877. /// Checks if a property already matches a desired value. Sets the property and
  878. /// notifies listeners only when necessary.
  879. /// </summary>
  880. /// <typeparam name="T">Type of the property.</typeparam>
  881. /// <param name="storage">Reference to a property with both getter and setter.</param>
  882. /// <param name="value">Desired value for the property.</param>
  883. /// <param name="propertyName">Name of the property used to notify listeners. This
  884. /// value is optional and can be provided automatically when invoked from compilers that
  885. /// support CallerMemberName.</param>
  886. /// <returns>True if the value was changed, false if the existing value matched the
  887. /// desired value.</returns>
  888. protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
  889. {
  890. if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
  891. storage = value;
  892. RaisePropertyChanged(propertyName);
  893. return true;
  894. }
  895. /// <summary>
  896. /// Checks if a property already matches a desired value. Sets the property and
  897. /// notifies listeners only when necessary.
  898. /// </summary>
  899. /// <typeparam name="T">Type of the property.</typeparam>
  900. /// <param name="storage">Reference to a property with both getter and setter.</param>
  901. /// <param name="value">Desired value for the property.</param>
  902. /// <param name="propertyName">Name of the property used to notify listeners. This
  903. /// value is optional and can be provided automatically when invoked from compilers that
  904. /// support CallerMemberName.</param>
  905. /// <param name="onChanged">Action that is called after the property value has been changed.</param>
  906. /// <returns>True if the value was changed, false if the existing value matched the
  907. /// desired value.</returns>
  908. protected virtual bool SetProperty<T>(ref T storage, T value, Action onChanged, [CallerMemberName] string propertyName = null)
  909. {
  910. if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
  911. storage = value;
  912. onChanged?.Invoke();
  913. RaisePropertyChanged(propertyName);
  914. return true;
  915. }
  916. /// <summary>
  917. /// Raises this object's PropertyChanged event.
  918. /// </summary>
  919. /// <param name="propertyName">Name of the property used to notify listeners. This
  920. /// value is optional and can be provided automatically when invoked from compilers
  921. /// that support <see cref="CallerMemberNameAttribute"/>.</param>
  922. protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
  923. {
  924. OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
  925. }
  926. /// <summary>
  927. /// Raises this object's PropertyChanged event.
  928. /// </summary>
  929. /// <param name="args">The PropertyChangedEventArgs</param>
  930. protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
  931. {
  932. PropertyChanged?.Invoke(this, args);
  933. }
  934. public bool CheckGrabImageCallbackEventIsHas(Action<ICogImage> action)
  935. {
  936. if (GrabImageCallbackEvent == null) return false;
  937. return GrabImageCallbackEvent.GetInvocationList().Contains(action);
  938. }
  939. public bool CheckImageCallbackEventIsHas(Action<ICogImage, TimeSpan, string> action)
  940. {
  941. if (ImageCallbackEvent == null) return false;
  942. return ImageCallbackEvent.GetInvocationList().Contains(action);
  943. }
  944. public bool CheckCameraConnectChangedEventIsHas(Action<Guid, bool> action)
  945. {
  946. if (CameraConnectChangedEvent == null) return false;
  947. return CameraConnectChangedEvent.GetInvocationList().Contains(action);
  948. }
  949. #endregion
  950. }
  951. }