SSZNCamera.cs 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088
  1. using Cognex.VisionPro;
  2. using Cognex.VisionPro.ImageFile;
  3. using Cognex.VisionPro.ToolBlock;
  4. using Cognex.VisionPro3D;
  5. using CSScripting;
  6. using Microsoft.Win32;
  7. using NPOI.SS.Formula.Functions;
  8. using SR7Link;
  9. using SRAPI;
  10. using SRCSharpDemo;
  11. using System;
  12. using System.Collections.Generic;
  13. using System.ComponentModel;
  14. using System.Diagnostics;
  15. using System.IO;
  16. using System.Linq;
  17. using System.Runtime.CompilerServices;
  18. using System.Runtime.InteropServices;
  19. using System.Text;
  20. using System.Threading;
  21. using System.Threading.Tasks;
  22. using System.Windows.Forms;
  23. using TeamAAS_VP.Enums;
  24. using TeamAAS_VP.Interfaces;
  25. using TeamAAS_VP.Models;
  26. namespace TeamAAS_VP.Core.Cameras
  27. {
  28. public class SSZNCamera : ICamera, INotifyPropertyChanged
  29. {
  30. #region 字段
  31. private Thread m_hReceiveThread;
  32. // 用于序列化对同一相机实例的操作,防止同一实例被并发操作
  33. //private readonly SemaphoreSlim _operationSemaphore = new SemaphoreSlim(1, 1);
  34. // 用于保护状态变量(例如 IsGrabbing)的并发访问
  35. private readonly object _stateLock = new object();
  36. private SR7ApiOneTimeCallbackImpl iSR7APi = new SR7ApiOneTimeCallbackImpl();
  37. public SRCSharpTools srcsharpTools = new SRCSharpTools();
  38. private SR7IFGetDataCallBack GetDataDelegate;
  39. private ErrConnectCallBack _errConnectDelegate;
  40. // 用于 Grab() 的一次性等待/完成通知
  41. private TaskCompletionSource<ICogImage> _grabTcs;
  42. #endregion
  43. #region define
  44. private int lastTotalPoints = 0; // 记录上次的总点数 / Record the last total points
  45. public int coutCallbackPoints;//统计总回调行数 / Count the total number of callback rows
  46. public uint profile16Bits = 0;//0:32bit 1:16bit
  47. //define
  48. public const int INVALID_VALUE_MIN = -1000000000;
  49. public const int INVALID_VALUE_MAX = 1000000000;
  50. #endregion
  51. #region Image cache variable
  52. //image cache
  53. public int[][] ImgBuff32; // 32-bit height data
  54. public short[][] ImgBuff16; // 16-bit height data
  55. public byte[][] GrayBuff; // Grayscale data
  56. public int[][] Encoder; // Encoder data
  57. public int coutCallbackPoints_B;
  58. #endregion
  59. #region 属性
  60. /// <summary>
  61. /// 是否是3D相机
  62. /// </summary>
  63. public bool Is3D { get; } = true;
  64. public CameraBrand CameraBrand { get => CameraBrand.SSZN; }
  65. public string Name { get; private set; }
  66. public Guid ID { get; private set; }
  67. public int Index { get; set; }
  68. public string ManufacturerName { get; private set; }
  69. public bool IsFindByIp { get; private set; }
  70. public string ModelName { get; private set; }
  71. public string SerialNumber { get; private set; }
  72. public string CameraIp { get; private set; }
  73. public CameraType CameraType { get; private set; }
  74. public UInt32 ImageWidth { get; private set; }
  75. public UInt32 ImageHeight { get; private set; }
  76. private bool _IsGrabbing;
  77. /// <summary>
  78. /// 正在采集
  79. /// </summary>
  80. public bool IsGrabbing
  81. {
  82. get { return _IsGrabbing; }
  83. private set { SetProperty(ref _IsGrabbing, value); }
  84. }
  85. private ICogImage _Image;
  86. public ICogImage Image
  87. {
  88. get { return _Image; }
  89. private set { SetProperty(ref _Image, value); }
  90. }
  91. public bool IsConnected { get; private set; }
  92. /// <summary>
  93. /// 采集用时
  94. /// </summary>
  95. public TimeSpan TotalTime { get; private set; }
  96. /// <summary>
  97. /// 错误信息
  98. /// </summary>
  99. public string ErrorMessage { get; private set; }
  100. private bool _CameraRevFinish;
  101. /// <summary>
  102. /// 图像接收完成
  103. /// </summary>
  104. public bool CameraRevFinish
  105. {
  106. get { return _CameraRevFinish; }
  107. set { SetProperty(ref _CameraRevFinish, value); }
  108. }
  109. /// <summary>
  110. /// 图像接收超时时间30s
  111. /// </summary>
  112. private double Timeout = 30;
  113. #endregion
  114. #region 事件
  115. public event Action<ICogImage, TimeSpan, string,Guid> ImageCallbackEvent;
  116. public event Action<Guid, bool> CameraConnectChangedEvent;
  117. #endregion
  118. public SSZNCamera(Guid id, int index, string name, string serialNumber, string cameraip, bool isFindByIp)
  119. {
  120. ID = id;
  121. Name = serialNumber;
  122. Index = index;
  123. CameraIp = cameraip;
  124. SerialNumber = serialNumber;
  125. IsFindByIp = isFindByIp;
  126. IsConnected = false;
  127. }
  128. #region 方法
  129. /// <summary>
  130. /// 外部设置批处理点数(例如从 UI 的 PlcPoint.Camera_Data)
  131. /// </summary>
  132. /// <param name="batchPoints"></param>
  133. public void SetBatchPoints(int batchPoints)
  134. {
  135. // 保证线程安全
  136. //_operationSemaphore.Wait();
  137. try
  138. {
  139. try
  140. {
  141. // 如果 SDK 对象支持 BatchPoints 字段,则设置
  142. iSR7APi.BatchPoints = batchPoints;
  143. }
  144. catch { }
  145. try
  146. {
  147. // 将值写回相机配置(保持与 OpenDevice 一致的行为)
  148. iSR7APi.SetParams(0, (int)SAVEPOWEROFF.ESAPO_SAVE, -1, SR7IF_SETTING_ITEM.BATCH_POINT, batchPoints);
  149. //SR7LinkFunc.SR7IF_StartMeasureWithCallback(0, 1);
  150. }
  151. catch { }
  152. }
  153. finally
  154. {
  155. //_operationSemaphore.Release();
  156. }
  157. }
  158. /// <summary>
  159. /// 获取设备
  160. /// </summary>
  161. /// <returns></returns>
  162. public static CameraInfo[] GetDevices()
  163. {
  164. List<CameraInfo> cameras = new List<CameraInfo>();
  165. try
  166. {
  167. if (!CheckSoftwareInstalled().isInstalled)
  168. {
  169. LogHelper.WriteLogInfo("未安装MVS");
  170. return cameras.ToArray();
  171. }
  172. SR7ApiOneTimeCallbackImpl sR7Api = new SR7ApiOneTimeCallbackImpl();
  173. List<string> cameraIPs = new List<string>();
  174. if (!sR7Api.SearchCameraIP(out cameraIPs))
  175. {
  176. return cameras.ToArray();
  177. }
  178. else
  179. {
  180. for (int i = 0; i < cameraIPs.Count; i++)
  181. {
  182. cameras.Add(new CameraInfo()
  183. {
  184. CameraNo = i + 1,
  185. CameraName = "SSZN_" + cameraIPs[i],
  186. CameraBrand = CameraBrand.SSZN,
  187. CameraType = CameraType.GIGE,
  188. ManufacturerName = "SSZN",
  189. Model = "SSZN_Model",
  190. SerialNumber = "SSZN_SerialNumber",
  191. CameraIp = cameraIPs[i],
  192. IsFindByIp = true,
  193. });
  194. }
  195. }
  196. }
  197. catch (Exception ex)
  198. {
  199. LogHelper.WriteLogError("搜索深视3D相机列表时出错!", ex);
  200. }
  201. return cameras.ToArray();
  202. }
  203. /// <summary>
  204. /// 检查相机软件是否安装
  205. /// </summary>
  206. /// <returns></returns>
  207. public static (bool isInstalled, string version) CheckSoftwareInstalled()
  208. {
  209. return (true, "");
  210. }
  211. /// <summary>
  212. /// 打开相机
  213. /// </summary>
  214. /// <returns></returns>
  215. /// <exception cref="Exception"></exception>
  216. public bool OpenDevice()
  217. {
  218. //_operationSemaphore.Wait();
  219. try
  220. {
  221. if (!iSR7APi.CameraBOnline)
  222. {
  223. //SR7Link.ErrConnectCallBack ErrConnectDelegate = new SR7Link.ErrConnectCallBack(ErrConnectFunc);
  224. //ErrConnectDelegate = new ErrConnectCallBack(ErrConnectFunc);
  225. //int nOpenRet = iSR7APi.Open(Index - 1, CameraIp, 2000, ErrConnectDelegate);
  226. if(_errConnectDelegate==null)
  227. {
  228. _errConnectDelegate=new ErrConnectCallBack(ErrConnectFunc);
  229. }
  230. int nOpenRet = iSR7APi.Open(Index - 1, CameraIp, 2000, _errConnectDelegate);
  231. if (nOpenRet == (int)SR7Link.SR7IF_ERROR.SR7IF_OK)
  232. {
  233. //设置相机参数,否则无法取图 / Set the camera parameters, otherwise you will not be able to take pictures
  234. //一次回调和无限回调可以设置批处理测量On,批处理数据接收无和循环 / One-time callback and infinite callback can set batch measurement On, batch data receiving None and loop
  235. //异步回调必须在Ed软件中设置 / Asynchronous callbacks must be set in the EdgeImaging software
  236. int nReadBastchValue = -1;
  237. int nSetParamRet = -1;
  238. int getParamRet = iSR7APi.GetParams(Index - 1, -1, SR7IF_SETTING_ITEM.BATCH_ON_OFF, out nReadBastchValue);
  239. if (nReadBastchValue != 1)
  240. {
  241. nSetParamRet = iSR7APi.SetParams(Index - 1, (int)SAVEPOWEROFF.ESAPO_SAVE, -1, SR7IF_SETTING_ITEM.BATCH_ON_OFF, 1);
  242. LogHelper.WriteLogInfo($"Set Batch On Off: {nSetParamRet}");
  243. }
  244. int _BatchPoints = 0;
  245. getParamRet = iSR7APi.GetParams(Index - 1, -1, SR7IF_SETTING_ITEM.BATCH_POINT, out _BatchPoints);
  246. iSR7APi.BatchPoints = _BatchPoints;
  247. nSetParamRet = iSR7APi.SetParams(Index - 1, (int)SAVEPOWEROFF.ESAPO_SAVE, -1, SR7IF_SETTING_ITEM.CYCLICAL_PATTERN, 0);
  248. int nSetParamRet1 = iSR7APi.SetParams(Index - 1, (int)SAVEPOWEROFF.ESAPO_SAVE, -1, SR7IF_SETTING_ITEM.SEGMENT_BUFER, 0);
  249. LogHelper.WriteLogInfo($"Set Batch Data Receive: {nSetParamRet1}{nSetParamRet1}");
  250. GetDataDelegate = new SR7IFGetDataCallBack(GetDataCallBack);
  251. iSR7APi.Init(Index - 1, 0, 2000, GetDataDelegate);
  252. }
  253. LogHelper.WriteLogInfo($"Connect Camera {nOpenRet} {GetSDKErrMsgByCode(nOpenRet)}");
  254. }
  255. if (!IsConnected)
  256. {
  257. if (iSR7APi.CameraAOnline)
  258. {
  259. CameraConnectChangedEvent?.Invoke(ID, true);
  260. }
  261. }
  262. IsConnected = iSR7APi.CameraAOnline;
  263. return IsConnected;
  264. }
  265. finally
  266. {
  267. //_operationSemaphore.Release();
  268. }
  269. }
  270. /// <summary>
  271. /// 打开相机异步
  272. /// </summary>
  273. /// <returns></returns>
  274. public Task<bool> OpenDeviceAsync()
  275. {
  276. return Task.Run(() =>
  277. {
  278. return OpenDevice();
  279. });
  280. }
  281. /// <summary>
  282. /// 关闭相机
  283. /// </summary>
  284. public void CloseDevice()
  285. {
  286. // ch:关闭设备 | en:Close Device
  287. //_operationSemaphore.Wait();
  288. try
  289. {
  290. if (iSR7APi == null)
  291. {
  292. return;
  293. }
  294. iSR7APi.Stop();
  295. int nRet = iSR7APi.Close();
  296. LogHelper.WriteLogInfo($"Close Camera: {nRet}{GetSDKErrMsgByCode(nRet)}");
  297. }
  298. finally
  299. {
  300. //_operationSemaphore.Release();
  301. }
  302. }
  303. /// <summary>
  304. /// 采集图像(同步阻塞实现:发送一次启动,等待回调或超时,返回图像)
  305. /// </summary>
  306. /// <returns></returns>
  307. public ICogImage Grab(bool isRealtime=true)
  308. {
  309. // 采用同步阻塞方式实现,一次采集等待回调完成或超时返回
  310. //_operationSemaphore.Wait();
  311. try
  312. {
  313. if (!isRealtime)
  314. return Image;
  315. DateTime now = DateTime.Now;
  316. while (!CameraRevFinish)
  317. {
  318. Thread.Sleep(10);
  319. if (DateTime.Now.Subtract(now).TotalSeconds>Timeout)
  320. {
  321. LogHelper.WriteLogDebug("图像采集超时");
  322. return null;
  323. }
  324. }
  325. return Image;
  326. }
  327. catch (Exception ex)
  328. {
  329. LogHelper.WriteLogError("Grab 出错", ex);
  330. return null;
  331. }
  332. finally
  333. {
  334. _grabTcs = null;
  335. //_operationSemaphore.Release();
  336. }
  337. }
  338. #region Init Memory
  339. public void InitImageBufferMem(bool isExistCameraB, int nWidth, int nHeight)
  340. {
  341. int nTotalPoints = nWidth * nHeight;
  342. if (nTotalPoints <= 0 || nTotalPoints <= lastTotalPoints)
  343. {
  344. for (int i = 0; i < 2; i++)
  345. {
  346. for (int j = 0; j < nTotalPoints; j++)
  347. {
  348. ImgBuff32[i][j] = -1000000000; // 初始化为 -1000000000
  349. }
  350. for (int j = 0; j < nTotalPoints; j++)
  351. {
  352. ImgBuff16[i][j] = 0;
  353. GrayBuff[i][j] = 0;
  354. }
  355. for (int j = 0; j < nHeight; j++)
  356. {
  357. Encoder[i][j] = 0;
  358. }
  359. }
  360. if (nTotalPoints == lastTotalPoints)
  361. {
  362. return;
  363. }
  364. // 避免重复初始化 / Avoid repeated initialization
  365. }
  366. // 如果 nTotalPoints 发生变化,才重新分配内存
  367. // If nTotalPoints changes, reallocate memory
  368. FreeMemory();
  369. ImgBuff32 = new int[2][];
  370. ImgBuff16 = new short[2][];
  371. GrayBuff = new byte[2][];
  372. Encoder = new int[2][];
  373. for (int i = 0; i < 2; i++)
  374. {
  375. ImgBuff32[i] = new int[nTotalPoints]; // 32-bit 高度数据 / height data
  376. for (int j = 0; j < nTotalPoints; j++)
  377. {
  378. ImgBuff32[i][j] = -1000000000; // 初始化为 -1000000000
  379. }
  380. ImgBuff16[i] = new short[nTotalPoints]; // 16-bit 高度数据 / height data
  381. GrayBuff[i] = new byte[nTotalPoints]; // 灰度数据 / grayscale data
  382. Encoder[i] = new int[nHeight]; // 编码器数据 / Encoder data
  383. }
  384. lastTotalPoints = nTotalPoints;
  385. }
  386. public void FreeMemory()
  387. {
  388. if (ImgBuff32 != null)
  389. {
  390. ImgBuff32 = null;
  391. ImgBuff16 = null;
  392. GrayBuff = null;
  393. Encoder = null;
  394. lastTotalPoints = 0;
  395. GC.Collect();
  396. }
  397. }
  398. #endregion
  399. /// <summary>
  400. /// 开始采集图像
  401. /// </summary>
  402. public void StartGrabbing()
  403. {
  404. //lock (_stateLock)
  405. //{
  406. // if (IsGrabbing)
  407. // return;
  408. // IsGrabbing = true;
  409. //}
  410. //m_hReceiveThread = new Thread(GetStreamThreadProc) { IsBackground = true };
  411. //m_hReceiveThread.Start();
  412. }
  413. /// <summary>
  414. /// 停止采集图像
  415. /// </summary>
  416. public void StopGrabbing()
  417. {
  418. //try
  419. //{
  420. // lock (_stateLock)
  421. // {
  422. // IsGrabbing = false;
  423. // }
  424. // Thread.Sleep(1000);
  425. // if (m_hReceiveThread != null)
  426. // {
  427. // m_hReceiveThread.Abort();
  428. // m_hReceiveThread = null;
  429. // }
  430. //}
  431. //catch (Exception)
  432. //{
  433. //}
  434. }
  435. /// <summary>
  436. /// 设置曝光时间
  437. /// </summary>
  438. /// <param name="ExposureTime"></param>
  439. /// <returns></returns>
  440. public bool SetExposureTime(float ExposureTime)
  441. {
  442. //_operationSemaphore.Wait();
  443. //try
  444. //{
  445. // if (!mvCameraAcq.bIsOpened)
  446. // return false;
  447. // mvCameraAcq.ExposureTime = (double)ExposureTime;
  448. // return true;
  449. //}
  450. //finally
  451. //{
  452. // _operationSemaphore.Release();
  453. //}
  454. return true;
  455. }
  456. /// <summary>
  457. /// 获取曝光时间
  458. /// </summary>
  459. /// <returns></returns>
  460. public float GetExposureTime()
  461. {
  462. //_operationSemaphore.Wait();
  463. //try
  464. //{
  465. // if (!mvCameraAcq.bIsOpened)
  466. // return 0;
  467. // return (float)mvCameraAcq.ExposureTime;
  468. //}
  469. //finally
  470. //{
  471. // _operationSemaphore.Release();
  472. //}
  473. return 0;
  474. }
  475. /// <summary>
  476. /// 设置增益
  477. /// </summary>
  478. /// <param name="Gain"></param>
  479. /// <returns></returns>
  480. public bool SetGain(float Gain)
  481. {
  482. //_operationSemaphore.Wait();
  483. //try
  484. //{
  485. // if (!mvCameraAcq.bIsOpened)
  486. // return false;
  487. // mvCameraAcq.AnalogGain = (double)Gain;
  488. // return true;
  489. //}
  490. //finally
  491. //{
  492. // _operationSemaphore.Release();
  493. //}
  494. return true;
  495. }
  496. /// <summary>
  497. /// 获取增益
  498. /// </summary>
  499. /// <returns></returns>
  500. public float GetGain()
  501. {
  502. //_operationSemaphore.Wait();
  503. //try
  504. //{
  505. // if (!mvCameraAcq.bIsOpened)
  506. // return 0;
  507. // return (float)mvCameraAcq.AnalogGain;
  508. //}
  509. //finally
  510. //{
  511. // _operationSemaphore.Release();
  512. //}
  513. return 0;
  514. }
  515. private void GetStreamThreadProc()
  516. {
  517. while (IsGrabbing)
  518. {
  519. try
  520. {
  521. Grab();
  522. ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage,ID);
  523. }
  524. catch (Exception)
  525. {
  526. }
  527. Thread.Sleep(10);
  528. }
  529. IsGrabbing = false;
  530. }
  531. /// <summary>
  532. ///
  533. /// </summary>
  534. /// <param name="nProfileWidth">单条轮廓宽度数据 / Returns a single contour width data</param>
  535. /// <param name="nHighlen">返回的批处理行数 / The number of rows in the batch returned</param>
  536. /// <param name="nFlag">回调函数执行状态,根据不同模式自定义 / Callback function execution status, customized according to different modes</param>
  537. /// <param name="nStatusCode">错误码,0无错误 / Error code, 0 no error</param>
  538. /// <param name="ProfileBits">Sync callback 0:32bit data, 1:16bit data</param>
  539. public void GetDataCallBack(int nProfileWidth, int nHighlen, int nFlag, int nStatusCode, int ProfileBits)
  540. {
  541. profile16Bits = (uint)ProfileBits;
  542. if (nStatusCode == 0)
  543. {
  544. Console.WriteLine($"Into GetDataFunc W:{nProfileWidth},H:{nHighlen},ErrCode:{nStatusCode}({GetSDKErrMsgByCode(nStatusCode)})");
  545. //这里拿到相机数据做显示,可以根据其他具体业务实现自己的逻辑
  546. //The camera data is obtained here for display, and you can implement your own logic according to other specific businesses
  547. int nTempWidth = nProfileWidth;// iSR7APi.GetProfileDataWidth();
  548. //双相机时,一次回调和异步回调nProfileWidth=3200,无限循环回调nProfileWidth=6400
  549. //For dual cameras, nProfileWidth=3200 for one-time callback and asynchronous callback, and nProfileWidth=6400 for infinite loop callback
  550. //if (iSR7APi.CameraBOnline && m_callbackMode == 2)//双相机 / dual camera
  551. // nTempWidth /= 2;
  552. int offset = coutCallbackPoints * nTempWidth;
  553. //int offset = 0;
  554. //iSR7APi.BatchPoints = nHighlen;
  555. SImagePro.SPointCloudHead pcHead = new SImagePro.SPointCloudHead(0, 0, 0, 0, 0);
  556. pcHead.width = (uint)nTempWidth;
  557. pcHead.height = (uint)iSR7APi.BatchPoints;
  558. pcHead.xInterval = iSR7APi.GetProfileData_XPitch();
  559. pcHead.yInterval = iSR7APi.GetProfileData_XPitch();
  560. //if (coutCallbackPoints != coutCallbackPoints_B)
  561. //{
  562. InitImageBufferMem(iSR7APi.CameraAOnline, nProfileWidth, iSR7APi.BatchPoints);
  563. // //ShowRGBImage(ImgBuff32[0], pcHead, pictureBoxA);
  564. //}
  565. //else if(coutCallbackPoints==0)
  566. //{
  567. // InitImageBufferMem(iSR7APi.CameraAOnline, nProfileWidth, iSR7APi.BatchPoints);
  568. //}
  569. // coutCallbackPoints_B = coutCallbackPoints;
  570. if (ProfileBits == 0)
  571. {
  572. //nHighlen = iSR7APi.BatchPoints;
  573. int[] tempHeightDataA = new int[nTempWidth * nHighlen];
  574. byte[] tempGrayDataA = new byte[nTempWidth * nHighlen];
  575. iSR7APi.GetData(tempHeightDataA, tempGrayDataA, Encoder[0], (int)pcHead.width, (int)nHighlen, 0);
  576. Array.Copy(tempHeightDataA, 0, ImgBuff32[0], 0, nTempWidth * nHighlen);
  577. Array.Copy(tempGrayDataA, 0, GrayBuff[0], 0, nTempWidth * nHighlen);
  578. if (ImgBuff32 != null && ImgBuff32.Length != 0 && ImgBuff32[0] != null)
  579. {
  580. //ShowRGBImage(ImgBuff32[0], pcHead, pictureBoxA);
  581. CogImage16Range cogImage16Range = SSZNCognexParser.SSZNParser.LoadSSZN3DImage(ImgBuff32[0], (int)pcHead.width, (int)pcHead.height, pcHead.xInterval, pcHead.yInterval);
  582. //CogImage16Range cogImage16Range;
  583. //var mRes=Create16Range(ImgBuff32[0], (int)pcHead.width, (int)pcHead.height, pcHead.xInterval, pcHead.yInterval,0.000001,0.001,out cogImage16Range);
  584. //if(mRes != null)
  585. //{
  586. // Image = cogImage16Range;
  587. // CameraRevFinish = true;
  588. // ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage, ID);
  589. //}
  590. Image = cogImage16Range;
  591. CameraRevFinish = true;
  592. ImageCallbackEvent?.Invoke(Image, TotalTime, ErrorMessage, ID);
  593. }
  594. }
  595. else
  596. {
  597. short[] temp16bitDataA = new short[nTempWidth * nHighlen];
  598. byte[] tempGrayDataA = new byte[nTempWidth * nHighlen];
  599. iSR7APi.GetData(temp16bitDataA, tempGrayDataA, Encoder[0], (int)pcHead.width, (int)nHighlen, 0);
  600. Array.Copy(temp16bitDataA, 0, ImgBuff16[0], offset, nTempWidth * nHighlen);
  601. Array.Copy(tempGrayDataA, 0, GrayBuff[0], offset, nTempWidth * nHighlen);
  602. int[] showtemp16bitDataA = new int[pcHead.width * pcHead.height];
  603. //ShowTiff16Data(ImgBuff16[0], showtemp16bitDataA);
  604. if (ImgBuff16 != null && ImgBuff16.Length != 0 && ImgBuff16[0] != null)
  605. {
  606. //ShowRGBImage(showtemp16bitDataA, pcHead, pictureBoxA);
  607. }
  608. }
  609. if (iSR7APi.CameraBOnline && ImgBuff32[1] != null)
  610. {
  611. if (ProfileBits == 0)
  612. {
  613. int[] tempHeightDataB = new int[nTempWidth * nHighlen];
  614. byte[] tempGrayDataB = new byte[nTempWidth * nHighlen];
  615. iSR7APi.GetData(tempHeightDataB, tempGrayDataB, Encoder[1], (int)pcHead.width, (int)nHighlen, 1);
  616. Array.Copy(tempHeightDataB, 0, ImgBuff32[1], offset, nTempWidth * nHighlen);
  617. Array.Copy(tempGrayDataB, 0, GrayBuff[1], offset, nTempWidth * nHighlen);
  618. //ShowRGBImage(ImgBuff32[1], pcHead, pictureBoxB);
  619. }
  620. else
  621. {
  622. short[] tempHeightDataB = new short[nTempWidth * nHighlen];
  623. byte[] tempGrayDataB = new byte[nTempWidth * nHighlen];
  624. iSR7APi.GetData(tempHeightDataB, tempGrayDataB, Encoder[1], (int)pcHead.width, (int)nHighlen, 1);
  625. Array.Copy(tempHeightDataB, 0, ImgBuff16[1], offset, nTempWidth * nHighlen);
  626. Array.Copy(tempGrayDataB, 0, GrayBuff[1], offset, nTempWidth * nHighlen);
  627. int[] showtemp16bitDataB = new int[pcHead.width * pcHead.height];
  628. //ShowTiff16Data(ImgBuff16[1], showtemp16bitDataB);
  629. //ShowRGBImage(showtemp16bitDataB, pcHead, pictureBoxB);
  630. }
  631. }
  632. coutCallbackPoints += nHighlen;
  633. }
  634. else
  635. {
  636. Console.WriteLine($"Data CallBack Exception:{nStatusCode}({GetSDKErrMsgByCode(nStatusCode)})");
  637. }
  638. }
  639. public void ErrConnectFunc(int dwDeviceId, int nErrCode)
  640. {
  641. LogHelper.WriteLogInfo($"Into ConnectExceptionCallback Error Code: {nErrCode}{GetSDKErrMsgByCode(nErrCode)}");
  642. iSR7APi.CameraAOnline = false;
  643. iSR7APi.CameraBOnline = false;
  644. //:1:Data overflow,3:Disconnect, 4:Wrong version
  645. //Non-asynchronous mode: -1 represents a general error, such as link failure, setup failure, data acquisition failure, etc., -1000;
  646. switch (nErrCode)
  647. {
  648. case 1:
  649. LogHelper.WriteLogInfo($"Into ConnectExceptionCallback Error Code: {nErrCode}{srcsharpTools.GetTranslation("CAMERA_EXCEPTION_1")}");
  650. break;
  651. case 3:
  652. LogHelper.WriteLogInfo($"Into ConnectExceptionCallback Error Code: {nErrCode}{srcsharpTools.GetTranslation("CAMERA_EXCEPTION_3")}");
  653. break;
  654. case 4:
  655. LogHelper.WriteLogInfo($"Into ConnectExceptionCallback Error Code: {nErrCode}{srcsharpTools.GetTranslation("CAMERA_EXCEPTION_3")}");
  656. break;
  657. case -1:
  658. LogHelper.WriteLogInfo($"Into ConnectExceptionCallback Error Code: {nErrCode}{srcsharpTools.GetTranslation("CAMERA_EXCEPTION_N1")}");
  659. break;
  660. default:
  661. break;
  662. }
  663. }
  664. public string GetSDKErrMsgByCode(int nErrCode)
  665. {
  666. string strErrMsg;
  667. switch ((SR7Link.SR7IF_ERROR)nErrCode)
  668. {
  669. case SR7IF_ERROR.SR7IF_ERROR_NOT_FOUND: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_NOT_FOUND"); break;
  670. case SR7IF_ERROR.SR7IF_ERROR_COMMAND: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_COMMAND"); break;
  671. case SR7IF_ERROR.SR7IF_ERROR_PARAMETER: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_PARAMETER"); break;
  672. case SR7IF_ERROR.SR7IF_ERROR_UNIMPLEMENTED: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_UNIMPLEMENTED"); break;
  673. case SR7IF_ERROR.SR7IF_ERROR_HANDLE: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_HANDLE"); break;
  674. case SR7IF_ERROR.SR7IF_ERROR_MEMORY: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_MEMORY"); break;
  675. case SR7IF_ERROR.SR7IF_ERROR_TIMEOUT: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_TIMEOUT"); break;
  676. case SR7IF_ERROR.SR7IF_ERROR_DATABUFFER: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_DATABUFFER"); break;
  677. case SR7IF_ERROR.SR7IF_ERROR_STREAM: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_STREAM"); break;
  678. case SR7IF_ERROR.SR7IF_ERROR_CLOSED: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_CLOSED"); break;
  679. case SR7IF_ERROR.SR7IF_ERROR_VERSION: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_VERSION"); break;
  680. case SR7IF_ERROR.SR7IF_ERROR_ABORT: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_ABORT"); break;
  681. case SR7IF_ERROR.SR7IF_ERROR_ALREADY_EXISTS: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_ALREADY_EXISTS"); break;
  682. case SR7IF_ERROR.SR7IF_ERROR_FRAME_LOSS: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_FRAME_LOSS"); break;
  683. case SR7IF_ERROR.SR7IF_ERROR_ROLL_DATA_OVERFLOW: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_ROLL_DATA_OVERFLOW"); break;
  684. case SR7IF_ERROR.SR7IF_ERROR_ROLL_BUSY: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_ROLL_BUSY"); break;
  685. case SR7IF_ERROR.SR7IF_ERROR_MODE: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_MODE"); break;
  686. case SR7IF_ERROR.SR7IF_ERROR_CAMERA_NOT_ONLINE: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR_CAMERA_NOT_ONLINE"); break;
  687. case SR7IF_ERROR.SR7IF_ERROR: strErrMsg = srcsharpTools.GetTranslation("SR7IF_ERROR"); break;
  688. case SR7IF_ERROR.SR7IF_NORMAL_STOP: strErrMsg = srcsharpTools.GetTranslation("SR7IF_NORMAL_STOP"); break;
  689. case SR7IF_ERROR.SR7IF_OK: strErrMsg = ""; break;
  690. default:
  691. strErrMsg = "";
  692. break;
  693. }
  694. return strErrMsg;
  695. }
  696. #endregion
  697. #region ECD生成CogImage16Range的方法
  698. /// <summary>
  699. /// 根据Int[]生成CogImage16Range
  700. /// </summary>
  701. /// <param name="iData">ECD数据源</param>
  702. /// <param name="iWidth">图像宽度</param>
  703. /// <param name="iHeight">图像高度</param>
  704. /// <param name="iScaleX">X方向分辨率</param>
  705. /// <param name="iScaleY">Y方向分辨率</param>
  706. /// <param name="iSrcScaleZ">ECD的Z方向分辨率</param>
  707. /// <param name="iDstScaleZ">CogImage16Range的Z方向分辨率</param>
  708. /// <param name="oImg">生成的CogImage16Range</param>
  709. /// <returns>报错讯息</returns>
  710. public static string Create16Range(int[] iData, int iWidth, int iHeight, double iScaleX, double iScaleY, double iSrcScaleZ, double iDstScaleZ, out CogImage16Range oImg)
  711. {
  712. try
  713. {
  714. bool mNoOverSize = true;
  715. #region 获取CogImage16Grey对象信息
  716. CogImage16Grey mSrcImg = new CogImage16Grey(iWidth, iHeight);
  717. ICogImage16PixelMemory mPm = mSrcImg.Get16GreyPixelMemory(CogImageDataModeConstants.ReadWrite, 0, 0, mSrcImg.Width, mSrcImg.Height);
  718. int mStride = mPm.Stride;
  719. #endregion
  720. #region Int[]数据转置写入CogImage16Grey的像素内存
  721. unsafe
  722. {
  723. int* mSrcDataPtr = (int*)Marshal.UnsafeAddrOfPinnedArrayElement(iData, 0);
  724. ushort* mDstDataPtr = (ushort*)mPm.Scan0;
  725. int mSurcIndex, mDestIndex;
  726. double mCurValue;
  727. for (int y = 0; y < iHeight; y++)
  728. {
  729. for (int x = 0; x < mStride; x++)
  730. {
  731. mSurcIndex = y * iWidth + x;
  732. mDestIndex = y * mStride + x;
  733. if (x < iWidth)
  734. {
  735. if (mSrcDataPtr[mSurcIndex] <= -1000000000)
  736. {
  737. mDstDataPtr[mDestIndex] = (ushort)0;
  738. }
  739. else
  740. {
  741. mCurValue = 1.0 * mSrcDataPtr[mSurcIndex] * (iSrcScaleZ / iDstScaleZ) + 32768; //0<=>65535
  742. if (ushort.MinValue <= mCurValue && mCurValue <= ushort.MaxValue)
  743. {
  744. mDstDataPtr[mDestIndex] = (ushort)(mCurValue);
  745. }
  746. else
  747. {
  748. mNoOverSize &= false;
  749. mDstDataPtr[mDestIndex] = (ushort)0;
  750. }
  751. }
  752. }
  753. else
  754. {
  755. mDstDataPtr[mDestIndex] = (ushort)0;
  756. }
  757. }
  758. }
  759. }
  760. #endregion
  761. #region 建立CogImage16Grey的初始坐标空间-Sensor3D
  762. CogTransform2DLinear mTf2D = new CogTransform2DLinear();
  763. double mScalingX = Math.Round(1.0 / iScaleX);
  764. double mScalingY = Math.Round(1.0 / iScaleY);
  765. double mRotationX = 2 * Math.PI;
  766. double mRotationY = 2 * Math.PI;
  767. double mTranslationX = 0d;
  768. double mTranslationY = 0d;
  769. mTf2D.SetScalingsRotationsTranslation(mScalingX, mScalingY, mRotationX, mRotationY, mTranslationX, mTranslationY);
  770. CogAddSpaceConstants mSpaceConstants = CogAddSpaceConstants.DuplicateIsError;
  771. mSrcImg.CoordinateSpaceTree.AddSpace("@", "Sensor2D", mTf2D, true, mSpaceConstants);
  772. #endregion
  773. #region 建立CogImage16Range的初始坐标空间-Sensor3D
  774. Cog3DMatrix3x3 m3DMatrix3x3 = new Cog3DMatrix3x3(iScaleX, 0, 0, 0, iScaleY, 0, 0, 0, iDstScaleZ);
  775. Cog3DVect3 m3DVect3 = new Cog3DVect3(-21, 0, 0);
  776. Cog3DTransformLinear mTf3D = new Cog3DTransformLinear(m3DMatrix3x3, m3DVect3);
  777. mTf3D = mTf3D.Inverse();
  778. #endregion
  779. oImg = new CogImage16Range(mSrcImg, 0, mTf3D);
  780. #region 判断是否存在像素值超限情况
  781. if (!mNoOverSize)
  782. {
  783. return "存在像素值超限情况";
  784. }
  785. else
  786. {
  787. return null;
  788. }
  789. #endregion
  790. }
  791. catch (Exception ex)
  792. {
  793. oImg = null;
  794. return ex.Message;
  795. }
  796. }
  797. /// <summary>
  798. /// 读取ECD格式文件的图像数据
  799. /// </summary>
  800. /// <param name="iFileName">文件路径</param>
  801. /// <param name="oData">图像数据</param>
  802. /// <param name="oWidth">图像宽度</param>
  803. /// <param name="oHeight">图像高度</param>
  804. /// <param name="oScaleX">X方向分辨率</param>
  805. /// <param name="oScaleY">Y方向分辨率</param>
  806. /// <returns>报错讯息</returns>
  807. public static string OpenEcd(string iFileName, out int[] oData, out int oWidth, out int oHeight, out double oScaleX, out double oScaleY)
  808. {
  809. try
  810. {
  811. #region 输出参数初始化
  812. oData = null;
  813. oWidth = 0;
  814. oHeight = 0;
  815. oScaleX = 0;
  816. oScaleY = 0;
  817. #endregion
  818. #region 文件存在判断
  819. if (!File.Exists(iFileName))
  820. {
  821. return "文件不存在";
  822. }
  823. #endregion
  824. #region 文件格式一致性判断
  825. string mExtension = Path.GetExtension(iFileName);
  826. if (mExtension != ".ecd")
  827. {
  828. return "文件格式不一致不存在";
  829. }
  830. #endregion
  831. #region 读取图像信息和数据
  832. #region 依据文件流创建二进制流读取器
  833. FileStream mFs = new FileStream(iFileName, FileMode.Open, FileAccess.Read);
  834. BinaryReader mBr = new BinaryReader(mFs);
  835. #endregion
  836. #region 文件头读取-获取点云规格(文件头共10240字节)
  837. uint mVersion = mBr.ReadUInt32();
  838. int mWidth = mBr.ReadInt32();
  839. int mHeight = mBr.ReadInt32();
  840. int mStride = ((mWidth + 3) / 4) * 4;
  841. if (mVersion == 2)
  842. {
  843. oScaleX = Math.Round(mBr.ReadDouble(), 3);
  844. oScaleY = Math.Round(mBr.ReadDouble(), 3);
  845. Int32 _Type = mBr.ReadInt32(); //无效位,为了数据对齐
  846. }
  847. else
  848. {
  849. Int32 _Type = mBr.ReadInt32(); //无效位,为了数据对齐
  850. oScaleX = Math.Round(mBr.ReadDouble(), 3);
  851. oScaleY = Math.Round(mBr.ReadDouble(), 3);
  852. }
  853. //读取剩余文件头
  854. mBr.ReadBytes(2552 * 4);
  855. #endregion
  856. oData = new int[mStride * mHeight];
  857. #region 图像高度数据读取
  858. unsafe
  859. {
  860. int* mDataPtr = (int*)Marshal.UnsafeAddrOfPinnedArrayElement(oData, 0);
  861. for (int y = 0; y < mHeight; y++)
  862. {
  863. for (int x = 0; x < mStride; x++)
  864. {
  865. if (x < mWidth)
  866. {
  867. mDataPtr[y * mStride + x] = mBr.ReadInt32();
  868. }
  869. else
  870. {
  871. mDataPtr[y * mStride + x] = -1000000000;
  872. }
  873. }
  874. }
  875. }
  876. #endregion
  877. oWidth = mStride;
  878. oHeight = mHeight;
  879. #region 关闭文件流和读取器
  880. mFs.Flush();
  881. mFs.Close();
  882. mBr.Close();
  883. #endregion
  884. #endregion
  885. return null;
  886. }
  887. catch (Exception ex)
  888. {
  889. oData = null;
  890. oWidth = 0;
  891. oHeight = 0;
  892. oScaleX = 0;
  893. oScaleY = 0;
  894. return ex.Message;
  895. }
  896. }
  897. /// <summary>
  898. /// 保存Vpro的IDB格式图像
  899. /// </summary>
  900. /// <param name="iImg">图像对象</param>
  901. /// <param name="iPath">保存路径</param>
  902. /// <returns></returns>
  903. public string SaveToIdb(ICogImage iImg, string iPath)
  904. {
  905. try
  906. {
  907. CogImageFile _MyImageFile = new CogImageFile();
  908. _MyImageFile.Open(iPath, CogImageFileModeConstants.Write);
  909. _MyImageFile.Append(iImg);
  910. _MyImageFile.Close();
  911. return null;
  912. }
  913. catch (Exception ex)
  914. {
  915. return ex.Message;
  916. }
  917. }
  918. #endregion
  919. #region 属性通知
  920. /// <summary>
  921. /// Occurs when a property value changes.
  922. /// </summary>
  923. public event PropertyChangedEventHandler PropertyChanged;
  924. /// <summary>
  925. /// Checks if a property already matches a desired value. Sets the property and
  926. /// notifies listeners only when necessary.
  927. /// </summary>
  928. /// <typeparam name="T">Type of the property.</typeparam>
  929. /// <param name="storage">Reference to a property with both getter and setter.</param>
  930. /// <param name="value">Desired value for the property.</param>
  931. /// <param name="propertyName">Name of the property used to notify listeners. This
  932. /// value is optional and can be provided automatically when invoked from compilers that
  933. /// support CallerMemberName.</param>
  934. /// <returns>True if the value was changed, false if the existing value matched the
  935. /// desired value.</returns>
  936. protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
  937. {
  938. if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
  939. storage = value;
  940. RaisePropertyChanged(propertyName);
  941. return true;
  942. }
  943. /// <summary>
  944. /// Checks if a property already matches a desired value. Sets the property and
  945. /// notifies listeners only when necessary.
  946. /// </summary>
  947. /// <typeparam name="T">Type of the property.</typeparam>
  948. /// <param name="storage">Reference to a property with both getter and setter.</param>
  949. /// <param name="value">Desired value for the property.</param>
  950. /// <param name="propertyName">Name of the property used to notify listeners. This
  951. /// value is optional and can be provided automatically when invoked from compilers that
  952. /// support CallerMemberName.</param>
  953. /// <param name="onChanged">Action that is called after the property value has been changed.</param>
  954. /// <returns>True if the value was changed, false if the existing value matched the
  955. /// desired value.</returns>
  956. protected virtual bool SetProperty<T>(ref T storage, T value, Action onChanged, [CallerMemberName] string propertyName = null)
  957. {
  958. if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
  959. storage = value;
  960. onChanged?.Invoke();
  961. RaisePropertyChanged(propertyName);
  962. return true;
  963. }
  964. /// <summary>
  965. /// Raises this object's PropertyChanged event.
  966. /// </summary>
  967. /// <param name="propertyName">Name of the property used to notify listeners. This
  968. /// value is optional and can be provided automatically when invoked from compilers
  969. /// that support <see cref="CallerMemberNameAttribute"/>.</param>
  970. protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
  971. {
  972. OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
  973. }
  974. /// <summary>
  975. /// Raises this object's PropertyChanged event.
  976. /// </summary>
  977. /// <param name="args">The PropertyChangedEventArgs</param>
  978. protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
  979. {
  980. PropertyChanged?.Invoke(this, args);
  981. }
  982. #endregion
  983. }
  984. }