SSZNCamera.cs 49 KB

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