革博士程序V1仓库
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

876 行
37 KiB

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Diagnostics;
  6. using System.Drawing;
  7. using System.Drawing.Imaging;
  8. using System.IO;
  9. using System.Linq;
  10. using System.Reflection;
  11. using System.Runtime.InteropServices;
  12. using System.Text;
  13. using System.Threading;
  14. using System.Threading.Tasks;
  15. using System.Timers;
  16. using System.Windows.Forms;
  17. using IKapBoardClassLibrary;
  18. using IKapC.NET;
  19. using LeatherApp.Device.CamerUtil;
  20. using LeatherApp.Interface;
  21. using Newtonsoft.Json.Linq;
  22. using OpenCvSharp;
  23. using OpenCvSharp.Dnn;
  24. using ErrorCode = IKapBoardClassLibrary.ErrorCode;
  25. namespace LeatherApp.Device
  26. {
  27. public class CamerCardDevIK : ABSCamerCardDev,IDisposable
  28. {
  29. [DllImport("user32.dll")]
  30. [return: MarshalAs(UnmanagedType.Bool)]
  31. private static extern bool IsWindow(IntPtr hWnd);
  32. [DllImport("kernel32.dll")]
  33. public static extern void CopyMemory(IntPtr Destination, IntPtr Source, int Length);
  34. // 相机句柄
  35. //private IKDeviceCL m_pDev = new IKDeviceCL();
  36. public IntPtr m_pDev = new IntPtr(-1);
  37. // 采集卡句柄
  38. public IntPtr m_pBoard = new IntPtr(-1);
  39. // 用户缓冲区,用于图像数据转换
  40. public IntPtr m_pUserBuffer = new IntPtr(-1);
  41. // 是否正在采集
  42. public volatile bool m_bGrabingImage = false;
  43. // 是否已更新用户缓冲区
  44. public volatile bool m_bUpdateImage = false;
  45. // 相机类型,0为GV相机,1为CL相机,2为CXP相机
  46. public int m_nType = -1;
  47. // 图像宽度
  48. public int m_nWidth = -1;
  49. // 图像高度
  50. public int m_nHeight = -1;
  51. // 像素位数
  52. public int m_nDepth = 8;
  53. // 图像通道数
  54. public int m_nChannels = 1;
  55. // 相机索引
  56. public int m_nDevIndex = -1;
  57. // 采集卡索引
  58. public int m_nBoardIndex = -1;
  59. // 相机缓冲区个数
  60. public int m_nFrameCount = 2;//只能1
  61. // 当前帧索引
  62. public int m_nCurFrameIndex = 0;
  63. // 相机缓冲区大小
  64. public int m_nBufferSize = 0;
  65. // 用户缓冲区锁
  66. public object m_mutexImage = new object();
  67. //显示图像控件句柄
  68. private PictureBox previewHwnd = null;
  69. //
  70. // 保存图像的文件名。
  71. public string m_strFileName = "C:\\CSharpImage.bmp";
  72. //
  73. private int scanIndex = 0; //实际拍照从1开始命名,因先加的1
  74. private string bmpSavePath;
  75. private Thread readerThread;
  76. private Queue<MyData> frameQueue =new Queue<MyData>();
  77. /// <summary>
  78. /// 曝光 3.00-10000.00
  79. /// </summary>
  80. public float ExposureTime { get; private set; }
  81. /// <summary>
  82. /// 增益 0-23.981199
  83. /// </summary>
  84. public float Gain { get; private set; }
  85. /// <summary>
  86. /// 帧率 0-429496.718750
  87. /// </summary>
  88. public float ResultingFrameRate { get; private set; }
  89. /// <summary>
  90. /// 图片大小
  91. /// </summary>
  92. public System.Drawing.Size size { get; private set; }
  93. /// <summary>
  94. /// 是否打开设备成功
  95. /// </summary>
  96. public bool IsInit { get; private set; } = false;
  97. //public string ErrInfo { get; private set; }
  98. //private System.Timers.Timer timer = new System.Timers.Timer();
  99. private int _scannerCardIndex = 0;//采集卡索引
  100. private int _scannerIndex=0;//相机索引(一个采集卡上可插多个相机)
  101. private IKDeviceInfo devInfo;
  102. BufferToImage hBuffer;
  103. private class MyData
  104. {
  105. public MyData(int _index,Mat _mat)
  106. {
  107. index= _index;
  108. mat = _mat;
  109. }
  110. public int index;
  111. public Mat mat;
  112. }
  113. // 设备类型枚举
  114. enum IKDeviceType
  115. {
  116. DEVICE_NIL = 0,
  117. DEVICE_CML,
  118. DEVICE_CXP,
  119. DEVICE_USB,
  120. DEVICE_GIGEVISION
  121. }
  122. // 设备信息结构体
  123. struct IKDeviceInfo
  124. {
  125. public IKDeviceType nType;
  126. public int nDevIndex;
  127. public int nBoardIndex;
  128. public string sDevName;
  129. }
  130. /// <summary>
  131. /// 读取缓存队列线程
  132. /// </summary>
  133. private void readDataThread()
  134. {
  135. MyData mydate;
  136. while (IsInit)
  137. {
  138. if (frameQueue.Count > 0) // 如果队列不为空则从队列中获取元素
  139. {
  140. lock (frameQueue)
  141. {
  142. mydate = frameQueue.Dequeue();
  143. }
  144. PhotoNumCacheEvent?.Invoke(frameQueue.Count);
  145. WarningEvent?.BeginInvoke(DateTime.Now,WarningEnum.Normal, $"相机({_scannerCardIndex})从缓存队列提取一帧图像({mydate.index}),开始回调(队列剩余帧数:{frameQueue.Count})...", null, null);
  146. ScanEvent?.Invoke(mydate.index, mydate.mat, _scannerCardIndex);
  147. WarningEvent?.BeginInvoke(DateTime.Now,WarningEnum.Normal, $"相机({_scannerCardIndex})图像({mydate.index})回调完成.", null, null);
  148. }
  149. else
  150. {
  151. Thread.Sleep(10);
  152. }
  153. }
  154. }
  155. public CamerCardDevIK( )
  156. {
  157. m_nType = 1;
  158. }
  159. public override bool open(int nBoardIndex,int nDevIndex)
  160. {
  161. if (IsInit) return true;
  162. _scannerCardIndex = nBoardIndex;
  163. WarningEvent?.BeginInvoke(DateTime.Now,WarningEnum.Normal, "open ....",null,null);
  164. try
  165. {
  166. closeDevice();
  167. scanIndex = 0;
  168. devInfo = new IKDeviceInfo();
  169. readerThread = new Thread(readDataThread); // 创建读取线程
  170. //
  171. uint nDevCount = 2;
  172. uint res = IKapCLib.ItkManGetDeviceCount(ref nDevCount);
  173. if (res != (uint)ItkStatusErrorId.ITKSTATUS_OK)
  174. {
  175. WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "ItkManGetDeviceCount failed");
  176. return false;
  177. }
  178. IKapCLib.ITKDEV_INFO pDevInfo = new IKapCLib.ITKDEV_INFO();
  179. IKapCLib.ITK_CL_DEV_INFO pClDevInfo = new IKapCLib.ITK_CL_DEV_INFO();
  180. for (uint i = 0; i < nDevCount; ++i)
  181. {
  182. IKapCLib.ItkManGetDeviceInfo(i, ref pDevInfo);
  183. if (pDevInfo.DeviceClass.CompareTo("CameraLink") == 0)
  184. {
  185. res = IKapCLib.ItkManGetCLDeviceInfo(i, ref pClDevInfo);
  186. //if (res != (uint)ItkStatusErrorId.ITKSTATUS_OK)
  187. // return;
  188. if ((int)pClDevInfo.BoardIndex == nBoardIndex)
  189. {
  190. devInfo.nType = IKDeviceType.DEVICE_CML;
  191. devInfo.nDevIndex = (int)i;
  192. devInfo.nBoardIndex = (int)pClDevInfo.BoardIndex;
  193. devInfo.sDevName = pDevInfo.FullName;
  194. }
  195. }
  196. }
  197. if(devInfo.nType != IKDeviceType.DEVICE_CML)
  198. {
  199. WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "对应索引相机不存在 failed");
  200. return false;
  201. }
  202. //
  203. res = IKapCLib.ItkDevOpen((uint)devInfo.nDevIndex
  204. , (int)(ItkDeviceAccessMode.ITKDEV_VAL_ACCESS_MODE_CONTROL)
  205. , ref m_pDev);
  206. if (!Check(res))
  207. {
  208. WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "Camera error:Open camera failed");
  209. return false;
  210. }
  211. //打开采集卡
  212. m_pBoard = IKapBoard.IKapOpen((uint)BoardType.IKBoardPCIE, (uint)devInfo.nBoardIndex);
  213. if (m_pBoard == new IntPtr(-1))
  214. {
  215. WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "IKapOpen failed");
  216. return false;
  217. }
  218. IsInit = true;
  219. readerThread.Start();
  220. return true;
  221. }
  222. catch (Exception ex)
  223. {
  224. WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, ex.Message);
  225. return false;
  226. }
  227. }
  228. public override void close()
  229. {
  230. if (!IsInit) return;
  231. try
  232. {
  233. IsInit = false;
  234. // 清除回调函数。
  235. UnRegisterCallback();
  236. // 关闭设备。
  237. CloseDevice();
  238. }
  239. catch { }
  240. }
  241. /// <summary>
  242. ///
  243. /// </summary>
  244. /// <param name="hwnd">显示图像控件句柄</param>
  245. /// <returns></returns>
  246. public override bool start(PictureBox preview_Hwnd,string bmp_save_path)
  247. {
  248. if (!IsInit) return false;
  249. WarningEvent?.Invoke(DateTime.Now,WarningEnum.Normal, "start ....");
  250. // 导入配置文件。
  251. string configFileName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\DevCfg\\" + (_scannerCardIndex==0?Config.Carmer1ConfigFilePath: Config.Carmer2ConfigFilePath);
  252. if (!File.Exists(configFileName))
  253. {
  254. WarningEvent?.Invoke(DateTime.Now,WarningEnum.High, "Fail to get configuration, using default setting!");
  255. return false;
  256. }
  257. var b=loadConfiguration(configFileName);
  258. WarningEvent?.Invoke(DateTime.Now,WarningEnum.Normal, "开始采集 ..."+b.ToString());
  259. this.previewHwnd= preview_Hwnd;
  260. this.bmpSavePath = bmp_save_path;
  261. //开始采集
  262. //第二个参数 nFrameCount 表示希望 IKapBoardClassLibrary 采集的帧数。
  263. //如果 nFrameCount = 1,IKapBoardClassLibrary 会从相机中采集一帧图像;
  264. //如果 nFrameCount = N 且 N> 1,则 IKapBoardClassLibrary 从相机中采集连续的 N 帧图 像;
  265. //如果 nFrameCount = 0,则 IKapBoardClassLibrary 开始连续采集图像。
  266. int ret;
  267. // 设置抓取模式,IKP_GRAB_NON_BLOCK为非阻塞模式
  268. //int grab_mode = (int)GrabMode.IKP_GRAB_NON_BLOCK;
  269. //ret = IKapBoard.IKapSetInfo(m_pBoard, (uint)INFO_ID.IKP_GRAB_MODE, grab_mode);
  270. //if (ret != (int)ErrorCode.IK_RTN_OK)
  271. // return false;
  272. //// 设置帧传输模式,IKP_FRAME_TRANSFER_SYNCHRONOUS_NEXT_EMPTY_WITH_PROTECT为同步保存模式
  273. //int transfer_mode = (int)FrameTransferMode.IKP_FRAME_TRANSFER_SYNCHRONOUS_NEXT_EMPTY_WITH_PROTECT;
  274. //ret = IKapBoard.IKapSetInfo(m_pBoard, (uint)INFO_ID.IKP_FRAME_TRANSFER_MODE, transfer_mode);
  275. //if (ret != (int)ErrorCode.IK_RTN_OK)
  276. // return false;
  277. //设置缓冲区格式
  278. ret = IKapBoard.IKapSetInfo(m_pBoard, (uint)INFO_ID.IKP_FRAME_COUNT, 1);//
  279. if (ret != (int)ErrorCode.IK_RTN_OK)
  280. return false;
  281. // 设置帧超时时间
  282. int timeout = -1;
  283. ret = IKapBoard.IKapSetInfo(m_pBoard, (uint)INFO_ID.IKP_TIME_OUT, timeout);
  284. if (ret != (int)ErrorCode.IK_RTN_OK)
  285. return false;
  286. // 设置采集模式。
  287. //
  288. // Set grab mode.
  289. int grab_mode = (int)GrabMode.IKP_GRAB_NON_BLOCK;
  290. ret = IKapBoard.IKapSetInfo(m_pBoard, (uint)INFO_ID.IKP_GRAB_MODE, grab_mode);
  291. if (ret != (int)ErrorCode.IK_RTN_OK)
  292. return false;
  293. // 设置传输模式。
  294. int transfer_mode = (int)FrameTransferMode.IKP_FRAME_TRANSFER_SYNCHRONOUS_NEXT_EMPTY_WITH_PROTECT;
  295. ret = IKapBoard.IKapSetInfo(m_pBoard, (uint)INFO_ID.IKP_FRAME_TRANSFER_MODE, transfer_mode);
  296. if (ret != (int)ErrorCode.IK_RTN_OK)
  297. return false;
  298. // 注册回调函数
  299. IntPtr hPtr = new IntPtr(-1);
  300. OnGrabStartProc = new IKapCallBackProc(OnGrabStartFunc);
  301. ret = IKapBoard.IKapRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_GrabStart, Marshal.GetFunctionPointerForDelegate(OnGrabStartProc), hPtr);
  302. if (ret != (int)ErrorCode.IK_RTN_OK)
  303. return false;
  304. OnFrameReadyProc = new IKapCallBackProc(OnFrameReadyFunc);
  305. ret = IKapBoard.IKapRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_FrameReady, Marshal.GetFunctionPointerForDelegate(OnFrameReadyProc), hPtr);
  306. if (ret != (int)ErrorCode.IK_RTN_OK)
  307. return false;
  308. OnFrameLostProc = new IKapCallBackProc(OnFrameLostFunc);
  309. ret = IKapBoard.IKapRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_FrameLost, Marshal.GetFunctionPointerForDelegate(OnFrameLostProc), hPtr);
  310. if (ret != (int)ErrorCode.IK_RTN_OK)
  311. return false;
  312. OnTimeoutProc = new IKapCallBackProc(OnTimeoutFunc);
  313. ret = IKapBoard.IKapRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_TimeOut, Marshal.GetFunctionPointerForDelegate(OnTimeoutProc), hPtr);
  314. if (ret != (int)ErrorCode.IK_RTN_OK)
  315. return false;
  316. OnGrabStopProc = new IKapCallBackProc(OnGrabStopFunc);
  317. ret = IKapBoard.IKapRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_GrabStop, Marshal.GetFunctionPointerForDelegate(OnGrabStopProc), hPtr);
  318. if (ret != (int)ErrorCode.IK_RTN_OK)
  319. return false;
  320. m_bUpdateImage = false;
  321. m_nCurFrameIndex = 0;
  322. ret = IKapBoard.IKapStartGrab(m_pBoard, 0);
  323. if (ret != (int)ErrorCode.IK_RTN_OK)
  324. return false;
  325. //createBuffer
  326. b = createBuffer();
  327. if (!b)
  328. return false;
  329. getParam();
  330. //
  331. m_bGrabingImage = true;
  332. return true;
  333. }
  334. /// <summary>
  335. /// 停止采集
  336. /// </summary>
  337. public override void stop()
  338. {
  339. if (!IsInit) return;
  340. try
  341. {
  342. // 停止图像采集。
  343. var ret = IKapBoard.IKapStopGrab(m_pBoard);
  344. clearBuffer();
  345. CheckIKapBoard(ret);
  346. }
  347. catch
  348. {
  349. return;
  350. }
  351. }
  352. /// <summary>
  353. /// num 因拍了一张后回传的,当前已经是1了
  354. /// </summary>
  355. /// <param name="num"></param>
  356. public override void resetScanIndex()
  357. {
  358. scanIndex = 0;//
  359. }
  360. public override void getParam()
  361. {
  362. if (!IsInit) return;
  363. string result;
  364. result = getFeatureValue("ExposureTime");
  365. if (!string.IsNullOrEmpty(result))
  366. ExposureTime = Convert.ToSingle(result);
  367. result = getFeatureValue("Gain");
  368. if (!string.IsNullOrEmpty(result))
  369. Gain = Convert.ToSingle(result);
  370. }
  371. /// <summary>
  372. ///
  373. /// </summary>
  374. /// <param name="exposureTime">曝光</param>
  375. /// <param name="gain">增益</param>
  376. /// <param name="resultingFrameRate">帧率</param>
  377. public override bool setParam(float exposureTime, float gain =-1, float resultingFrameRate =-1)
  378. {
  379. if (!IsInit) return false;
  380. bool change = false;
  381. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Normal, $"ExposureTime: {exposureTime},{ExposureTime}");
  382. if (exposureTime != ExposureTime && exposureTime != -1)
  383. {
  384. if(setFeatureValue("ExposureTime", exposureTime.ToString()))
  385. change = true;
  386. }
  387. //WarningEvent?.Invoke(DateTime.Now,WarningEnum.Normal, $"Gain: {gain},{Gain}");
  388. if (gain != Gain && gain != -1)
  389. {
  390. if (setFeatureValue("Gain", gain.ToString()))
  391. change = true;
  392. }
  393. //if (resultingFrameRate != ResultingFrameRate && resultingFrameRate != -1)
  394. //{
  395. // cDeviceParam.SetFloatValue("AcquisitionFrameRate", resultingFrameRate);
  396. // change = true;
  397. //}
  398. //
  399. if (change)
  400. getParam();
  401. return change;
  402. }
  403. public void Dispose()
  404. {
  405. stop();
  406. close();
  407. }
  408. //---------------
  409. /* @brief:设置行触发参数。
  410. *
  411. * @brief:Set line trigger parameters. */
  412. void SetLineTrigger()
  413. {
  414. int ret = (int)ErrorCode.IK_RTN_OK;
  415. // 设置CC1信号源。
  416. //
  417. // Set CC1 signal source.
  418. ret = IKapBoard.IKapSetInfo(m_pBoard, (uint)INFO_ID.IKP_CC1_SOURCE, (int)CCSource.IKP_CC_SOURCE_VAL_INTEGRATION_SIGNAL1);
  419. CheckIKapBoard(ret);
  420. // 设置积分控制方法触发信号源。
  421. //
  422. // Set integration control method trigger source.
  423. ret = IKapBoard.IKapSetInfo(m_pBoard, (uint)INFO_ID.IKP_INTEGRATION_TRIGGER_SOURCE, (int)IntegrationTriggerSource.IKP_INTEGRATION_TRIGGER_SOURCE_VAL_SHAFT_ENCODER1);
  424. CheckIKapBoard(ret);
  425. }
  426. /* @brief:清除回调函数。
  427. *
  428. * @brief:Unregister callback functions. */
  429. private void UnRegisterCallback()
  430. {
  431. int ret = (int)ErrorCode.IK_RTN_OK;
  432. ret = IKapBoard.IKapUnRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_GrabStart);
  433. ret = IKapBoard.IKapUnRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_FrameReady);
  434. ret = IKapBoard.IKapUnRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_FrameLost);
  435. ret = IKapBoard.IKapUnRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_TimeOut);
  436. ret = IKapBoard.IKapUnRegisterCallback(m_pBoard, (uint)CallBackEvents.IKEvent_GrabStop);
  437. }
  438. /* @brief:关闭设备。
  439. *
  440. * @brief:Close device. */
  441. private void CloseDevice()
  442. {
  443. // 关闭采集卡设备。
  444. //
  445. // Close frame grabber device.
  446. if (!m_pBoard.Equals(-1))
  447. {
  448. IKapBoard.IKapClose(m_pBoard);
  449. m_pBoard = (IntPtr)(-1);
  450. }
  451. }
  452. /* @brief:判断 IKapBoard 函数是否成功调用。
  453. * @param[in] ret:函数返回值。
  454. *
  455. * @brief:Determine whether the IKapBoard function is called successfully.
  456. * @param[in] ret:Function return value. */
  457. static void CheckIKapBoard(int ret)
  458. {
  459. if (ret != (int)ErrorCode.IK_RTN_OK)
  460. {
  461. string sErrMsg = "";
  462. IKapBoard.IKAPERRORINFO tIKei = new IKapBoardClassLibrary.IKapBoard.IKAPERRORINFO();
  463. // 获取错误码信息。
  464. IKapBoard.IKapGetLastError(ref tIKei, true);
  465. // 打印错误信息。
  466. sErrMsg = string.Concat("Error",
  467. sErrMsg,
  468. "Board Type\t = 0x", tIKei.uBoardType.ToString("X4"), "\n",
  469. "Board Index\t = 0x", tIKei.uBoardIndex.ToString("X4"), "\n",
  470. "Error Code\t = 0x", tIKei.uErrorCode.ToString("X4"), "\n"
  471. );
  472. throw new Exception(sErrMsg);
  473. }
  474. }
  475. #region Callback
  476. delegate void IKapCallBackProc(IntPtr pParam);
  477. /* @brief:本函数被注册为一个回调函数。当图像采集开始时,函数被调用。
  478. *
  479. * @brief:This function is registered as a callback function. When starting grabbing images, the function will be called. */
  480. private IKapCallBackProc OnGrabStartProc;
  481. /* @brief:本函数被注册为一个回调函数。当采集丢帧时,函数被调用。
  482. *
  483. * @brief:This function is registered as a callback function. When grabbing frame lost, the function will be called. */
  484. private IKapCallBackProc OnFrameLostProc;
  485. /* @brief:本函数被注册为一个回调函数。当图像采集超时时,函数被调用。
  486. *
  487. * @brief:This function is registered as a callback function. When grabbing images time out, the function will be called. */
  488. private IKapCallBackProc OnTimeoutProc;
  489. /* @brief:本函数被注册为一个回调函数。当一帧图像采集完成时,函数被调用。
  490. *
  491. * @brief:This function is registered as a callback function. When a frame of image grabbing ready, the function will be called. */
  492. private IKapCallBackProc OnFrameReadyProc;
  493. /* @brief:本函数被注册为一个回调函数。当图像采集停止时,函数被调用。
  494. *
  495. * @brief:This function is registered as a callback function. When stopping grabbing images, the function will be called. */
  496. private IKapCallBackProc OnGrabStopProc;
  497. #endregion
  498. #region Callback
  499. /* @brief:本函数被注册为一个回调函数。当图像采集开始时,函数被调用。
  500. * @param[in] pParam:输入参数。
  501. *
  502. * @brief:This function is registered as a callback function. When starting grabbing images, the function will be called.
  503. * @param[in] pParam:Input parameter. */
  504. public void OnGrabStartFunc(IntPtr pParam)
  505. {
  506. WarningEvent?.BeginInvoke(DateTime.Now,WarningEnum.Normal, "图像开始采集...", null, null);
  507. }
  508. /* @brief:本函数被注册为一个回调函数。当采集丢帧时,函数被调用。
  509. * @param[in] pParam:输入参数。
  510. *
  511. * @brief:This function is registered as a callback function. When grabbing frame lost, the function will be called.
  512. * @param[in] pParam:Input parameter. */
  513. public void OnFrameLostFunc(IntPtr pParam)
  514. {
  515. WarningEvent?.BeginInvoke(DateTime.Now,WarningEnum.High, $"相机({_scannerCardIndex})采集图像({scanIndex})丢帧(Image frame lost),急停告警,需结束重新开始!!!!", null, null);
  516. }
  517. /* @brief:本函数被注册为一个回调函数。当图像采集超时时,函数被调用。
  518. * @param[in] pParam:输入参数。
  519. *
  520. * @brief:This function is registered as a callback function. When grabbing images time out, the function will be called.
  521. * @param[in] pParam:Input parameter. */
  522. public void OnTimeoutFunc(IntPtr pParam)
  523. {
  524. WarningEvent?.BeginInvoke(DateTime.Now,WarningEnum.High, $"相机({_scannerCardIndex})采集图像({scanIndex})超时(Grab image timeout),请检查采集卡!", null, null);
  525. }
  526. /* @brief:本函数被注册为一个回调函数。当一帧图像采集完成时,函数被调用。
  527. * @param[in] pParam:输入参数。
  528. *
  529. * @brief:This function is registered as a callback function. When a frame of image grabbing ready, the function will be called.
  530. * @param[in] pParam:Input parameter. */
  531. public void OnFrameReadyFunc(IntPtr pParam)
  532. {
  533. try
  534. {
  535. Stopwatch stopwatch = Stopwatch.StartNew();
  536. stopwatch.Start();
  537. int index = ++scanIndex;
  538. WarningEvent?.BeginInvoke(DateTime.Now, WarningEnum.Normal, $"OnFrameReadyFunc 相机({_scannerCardIndex})一帧图像({index})采集完成,正在加入队列({frameQueue.Count})...", null, null);
  539. IntPtr hPtr = new IntPtr(-1);
  540. // 获取当前帧状态
  541. var ret = IKapBoard.IKapGetInfo(m_pBoard, (uint)INFO_ID.IKP_CURRENT_BUFFER_INDEX, ref m_nCurFrameIndex);
  542. if (ret != (int)ErrorCode.IK_RTN_OK)
  543. return;
  544. //IKapBoard.IKAPBUFFERSTATUS status = new IKapBoard.IKAPBUFFERSTATUS();
  545. //IKapBoard.IKapGetBufferStatus(m_pBoard, m_nCurFrameIndex, ref status);
  546. //var uFull = status.uFull;
  547. //if (uFull == 1)//指明缓冲区是否为满
  548. {
  549. IKapBoard.IKapGetBufferAddress(m_pBoard, m_nCurFrameIndex, ref hPtr);
  550. //Monitor.Enter(m_mutexImage);
  551. lock (m_mutexImage)
  552. {
  553. CopyMemory(m_pUserBuffer, hPtr, m_nBufferSize);
  554. m_bUpdateImage = true;
  555. Mat mat = new Mat(m_nHeight, m_nWidth, MatType.CV_8UC3, m_pUserBuffer);
  556. //var bmp = hBuffer.toBmp(m_pUserBuffer);
  557. //Mat mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(bmp);
  558. //bmp.Dispose();
  559. //bmp = null;
  560. //Monitor.Enter(frameQueue);
  561. lock (frameQueue)
  562. frameQueue.Enqueue(new MyData(index, mat.Clone()));
  563. PhotoNumCacheEvent?.BeginInvoke(frameQueue.Count, null, null);
  564. }
  565. }
  566. //m_nCurFrameIndex++;
  567. //m_nCurFrameIndex = m_nCurFrameIndex % m_nFrameCount;
  568. stopwatch.Stop();
  569. WarningEvent?.BeginInvoke(DateTime.Now, WarningEnum.Normal, $"OnFrameReadyFunc 相机({_scannerCardIndex})一帧图像({index})已加入队列({frameQueue.Count}).缓冲区索引={m_nCurFrameIndex};用时:{stopwatch.ElapsedMilliseconds}ms", null, null);
  570. }
  571. catch (Exception ex)
  572. {
  573. WarningEvent?.BeginInvoke(DateTime.Now, WarningEnum.High, $"OnFrameReadyFunc 异常,急停告警,需结束重新开始!!!!{ex.Message}\r\n{ex.StackTrace}", null, null);
  574. }
  575. }
  576. /* @brief:本函数被注册为一个回调函数。当图像采集停止时,函数被调用。
  577. * @param[in] pParam:输入参数。
  578. *
  579. * @brief:This function is registered as a callback function. When stopping grabbing images, the function will be called.
  580. * @param[in] pParam:Input parameter. */
  581. public void OnGrabStopFunc(IntPtr pParam)
  582. {
  583. Console.WriteLine("Stop grabbing image");
  584. }
  585. #endregion
  586. private byte[] bmp2bytes(Bitmap bmp)
  587. {
  588. MemoryStream ms = new MemoryStream();
  589. bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
  590. byte[] bytes = ms.GetBuffer(); //byte[] bytes= ms.ToArray(); 这两句都可以,至于区别么,下面有解释
  591. ms.Close();
  592. bmp.Dispose();
  593. return bytes;
  594. }
  595. private Bitmap bytes2bmp(byte[] bytes)
  596. {
  597. MemoryStream ms1 = new MemoryStream(bytes);
  598. Bitmap bm = (Bitmap)Image.FromStream(ms1);
  599. ms1.Close();
  600. return bm;
  601. }
  602. /*
  603. * @brief:设置相机特征值
  604. * @param [in] featureName:特征名[ExposureTime,Gain]
  605. * @param [in] featureValue:特征值
  606. * @return: 是否设置成功
  607. */
  608. private bool setFeatureValue(string featureName, string featureValue)
  609. {
  610. IntPtr itkFeature = new IntPtr(-1);
  611. uint nType = 0;
  612. uint res = IKapCLib.ItkDevAllocFeature(m_pDev, featureName, ref itkFeature);
  613. if (!Check(res))
  614. {
  615. WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"setFeatureValue({featureName},{featureValue}) Camera error:Allocate feature failed");
  616. return false;
  617. }
  618. res = IKapCLib.ItkFeatureGetType(itkFeature, ref nType);
  619. if (!Check(res))
  620. {
  621. WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"setFeatureValue({featureName},{featureValue}) Camera error:Get feature type failed");
  622. return false;
  623. }
  624. switch (nType)
  625. {
  626. case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_INT32:
  627. res = IKapCLib.ItkFeatureSetInt32(itkFeature, Convert.ToInt32(featureValue));
  628. break;
  629. case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_INT64:
  630. res = IKapCLib.ItkFeatureSetInt64(itkFeature, Convert.ToInt64(featureValue));
  631. break;
  632. case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_FLOAT:
  633. case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_DOUBLE:
  634. res = IKapCLib.ItkFeatureSetDouble(itkFeature, Convert.ToDouble(featureValue));
  635. break;
  636. case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_ENUM:
  637. case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_STRING:
  638. res = IKapCLib.ItkFeatureFromString(itkFeature, featureValue);
  639. break;
  640. case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_COMMAND:
  641. res = IKapCLib.ItkFeatureExecuteCommand(itkFeature);
  642. break;
  643. }
  644. if (!Check(res))
  645. {
  646. WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"setFeatureValue({featureName},{featureValue}) Camera error:Set feature failed:" + res);
  647. return false;
  648. }
  649. return true;
  650. }
  651. private string getFeatureValue(string featureName)
  652. {
  653. IntPtr itkFeature = new IntPtr(-1);
  654. uint nType = 0;
  655. uint res = IKapCLib.ItkDevAllocFeature(m_pDev, featureName, ref itkFeature);
  656. if (!Check(res))
  657. {
  658. WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"getFeatureValue({featureName}) Camera error:Allocate feature failed");
  659. return "";
  660. }
  661. res = IKapCLib.ItkFeatureGetType(itkFeature, ref nType);
  662. if (!Check(res))
  663. {
  664. WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"getFeatureValue({featureName}) Camera error:Get feature type failed");
  665. return "";
  666. }
  667. switch (nType)
  668. {
  669. case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_INT32:
  670. int result = 0;
  671. res = IKapCLib.ItkFeatureGetInt32(itkFeature,ref result);
  672. if (!Check(res))
  673. {
  674. WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"getFeatureValue({featureName}) Camera error:Get feature failed:" + res);
  675. return "";
  676. }
  677. return result.ToString();
  678. case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_INT64:
  679. long resultL = 0;
  680. res = IKapCLib.ItkFeatureGetInt64(itkFeature, ref resultL);
  681. if (!Check(res))
  682. {
  683. WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"getFeatureValue({featureName}) Camera error:Get feature failed:" + res);
  684. return "";
  685. }
  686. return resultL.ToString();
  687. case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_FLOAT:
  688. case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_DOUBLE:
  689. double resultD = 0;
  690. res = IKapCLib.ItkFeatureGetDouble(itkFeature, ref resultD);
  691. if (!Check(res))
  692. {
  693. WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"getFeatureValue({featureName}) Camera error:Get feature failed:" + res);
  694. return "";
  695. }
  696. return resultD.ToString();
  697. case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_ENUM:
  698. case (uint)ItkFeatureType.ITKFEATURE_VAL_TYPE_STRING:
  699. string results = "";
  700. res = IKapCLib.ItkFeatureFromString(itkFeature, results);
  701. if (!Check(res))
  702. {
  703. WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"getFeatureValue({featureName}) Camera error:Get feature failed:" + res);
  704. return "";
  705. }
  706. return results;
  707. }
  708. if (!Check(res))
  709. {
  710. WarningEvent?.Invoke(DateTime.Now,WarningEnum.Low, $"getFeatureValue({featureName}) Camera error:Get feature failed:" + res);
  711. return "";
  712. }
  713. return "";
  714. }
  715. public override double[] getFeatureRangeValue(string featureName)
  716. {
  717. switch (featureName)
  718. {
  719. case "ExposureTime":
  720. //return new double[2] {3.2,63997};
  721. return new double[2] { 10, 200 };
  722. case "Gain":
  723. return new double[2] { 0.01, 8.00 };
  724. default: return new double[0] { };
  725. }
  726. }
  727. /*
  728. *@brief:检查错误码
  729. *@param [in] err:错误码
  730. *@return:是否错误
  731. */
  732. private static bool Check(uint err)
  733. {
  734. if (err != (uint)ItkStatusErrorId.ITKSTATUS_OK)
  735. {
  736. System.Diagnostics.Debug.WriteLine("Error code: {0}.\n", err.ToString("x8"));
  737. return false;
  738. }
  739. return true;
  740. }
  741. //----
  742. private bool isOpen()
  743. {
  744. return m_pDev != new IntPtr(-1) && m_pBoard != new IntPtr(-1);
  745. }
  746. private bool closeDevice()
  747. {
  748. frameQueue.Clear();
  749. if (isOpen())
  750. {
  751. IKapBoard.IKapClose(m_pBoard);
  752. IKapCLib.ItkDevClose(m_pDev);
  753. }
  754. return true;
  755. }
  756. private bool loadConfiguration(string sFilePath)
  757. {
  758. int ret = IKapBoard.IKapLoadConfigurationFromFile(m_pBoard, sFilePath);
  759. return ret == (int)ErrorCode.IK_RTN_OK;
  760. }
  761. private bool createBuffer()
  762. {
  763. int ret = (int)ErrorCode.IK_RTN_OK;
  764. int nImageType = 0;
  765. ret = IKapBoard.IKapGetInfo(m_pBoard, (uint)INFO_ID.IKP_IMAGE_WIDTH, ref m_nWidth);
  766. if (ret != (int)ErrorCode.IK_RTN_OK)
  767. return false;
  768. ret = IKapBoard.IKapGetInfo(m_pBoard, (uint)INFO_ID.IKP_IMAGE_HEIGHT, ref m_nHeight);
  769. if (ret != (int)ErrorCode.IK_RTN_OK)
  770. return false;
  771. ret = IKapBoard.IKapGetInfo(m_pBoard, (uint)INFO_ID.IKP_IMAGE_TYPE, ref nImageType);
  772. if (ret != (int)ErrorCode.IK_RTN_OK)
  773. return false;
  774. ret = IKapBoard.IKapGetInfo(m_pBoard, (uint)INFO_ID.IKP_DATA_FORMAT, ref m_nDepth);
  775. if (ret != (int)ErrorCode.IK_RTN_OK)
  776. return false;
  777. ret = IKapBoard.IKapGetInfo(m_pBoard, (uint)INFO_ID.IKP_FRAME_SIZE, ref m_nBufferSize);
  778. if (ret != (int)ErrorCode.IK_RTN_OK)
  779. return false;
  780. switch (nImageType)
  781. {
  782. case 0:
  783. m_nChannels = 1;
  784. break;
  785. case 1:
  786. case 3:
  787. m_nChannels = 3;
  788. break;
  789. case 2:
  790. case 4:
  791. m_nChannels = 4;
  792. break;
  793. }
  794. WarningEvent?.Invoke(DateTime.Now,WarningEnum.Normal, $"图片类型:{nImageType},通道数:{m_nChannels},size:{m_nWidth}*{m_nHeight}");
  795. m_pUserBuffer = Marshal.AllocHGlobal(m_nBufferSize);
  796. //
  797. hBuffer = new BufferToImage(m_nBufferSize , m_nDepth, m_nChannels , m_nWidth, m_nHeight);
  798. return true;
  799. }
  800. private void clearBuffer()
  801. {
  802. if (m_pUserBuffer == new IntPtr(-1))
  803. return;
  804. Marshal.FreeHGlobal(m_pUserBuffer);
  805. m_pUserBuffer = new IntPtr(-1);
  806. }
  807. }
  808. }