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

4051 行
198 KiB

  1. #define Online
  2. #define Online_defect
  3. //#define Online_One
  4. using BarTenderPrint;
  5. using CCWin.SkinControl;
  6. using CCWin.Win32;
  7. using CCWin.Win32.Const;
  8. using DocumentFormat.OpenXml.Spreadsheet;
  9. using GeBoShi.ImageDefect;
  10. using GeBoShi.UI.InageShow;
  11. using HalconDotNet;
  12. using HZH_Controls;
  13. using HZH_Controls.Forms;
  14. using MaiMuControl.Device;
  15. using MaiMuControl.Device.CamDev;
  16. using MaiMuControl.Device.IOCardDev;
  17. using MaiMuControl.Device.IOCardDev.Advantech;
  18. using MaiMuControl.Device.LightDev;
  19. using MaiMuControl.Device.LightDev.CST;
  20. using MaiMuControl.Device.LightDev.Rsee;
  21. using MaiMuControl.Device.PlcDev;
  22. using MaiMuControl.SysStatusMgr.CloudMgr;
  23. using MaiMuControl.SysStatusMgr.StatusMgr;
  24. using MaiMuControl.SysStatusMgr.UserMgr;
  25. using MaiMuControl.Utils;
  26. using Models;
  27. using Newtonsoft.Json;
  28. using Newtonsoft.Json.Linq;
  29. using OpenCvSharp;
  30. using OpenCvSharp.Extensions;
  31. using S7.Net;
  32. using SqlSugar;
  33. using System;
  34. using System.Collections;
  35. using System.Collections.Concurrent;
  36. using System.Collections.Generic;
  37. using System.Data;
  38. using System.Diagnostics;
  39. using System.Drawing;
  40. using System.Drawing.Imaging;
  41. using System.IO;
  42. using System.IO.Ports;
  43. using System.Linq;
  44. using System.Net.Mail;
  45. using System.Threading;
  46. using System.Threading.Tasks;
  47. using System.Windows.Forms;
  48. using System.Windows.Forms.DataVisualization.Charting;
  49. using System.Windows.Forms.VisualStyles;
  50. using ToolKits.Disk;
  51. using static System.Windows.Forms.VisualStyles.VisualStyleElement.TaskbarClock;
  52. namespace GeBoShi.SysCtrl
  53. {
  54. /// <summary>
  55. /// 主系统控制
  56. /// </summary>
  57. public class SysMgr
  58. {
  59. #region singleton实例化
  60. private static SysMgr _instance;
  61. private static readonly object _lock = new object();
  62. public static SysMgr Instance
  63. {
  64. get
  65. {
  66. if (_instance == null)
  67. {
  68. lock (_lock)
  69. {
  70. if (_instance == null)
  71. {
  72. _instance = new SysMgr();
  73. }
  74. }
  75. }
  76. return _instance;
  77. }
  78. }
  79. #endregion
  80. #region 私有
  81. //系统状态
  82. private StatusMgr statusMgr;
  83. public StatusMgr StatusMgr { get { return statusMgr; } }
  84. //用户管理
  85. private UserMgr userMgr;
  86. public UserMgr UserMgr { get { return userMgr; } }
  87. //系统配置管理
  88. private ConfMgr confMgr;
  89. //图像处理
  90. private DefectLib defectLib;
  91. public DefectLib DefectLib { get { return defectLib; } }
  92. //产品检测列表
  93. private List<string> productCodeList = new List<string>();
  94. public List<string> ProductCodeList { get { return productCodeList; } }
  95. //产品ID列表
  96. private List<int> productIdList = new List<int>();
  97. public List<int> ProductIdList { get { return productIdList; } }
  98. /// <summary>
  99. /// 当前产品
  100. /// </summary>
  101. private Models.Product CurrProductModel = null;
  102. //数据锁
  103. private object lockCurrKey = new object();
  104. //当前运行数据key
  105. private int currKey = 0;
  106. //线程管控
  107. private Hashtable htTask = new Hashtable();//默认单线程写入不用lock, 多线程安全同步读取用Synchronized
  108. //是否处理完成
  109. private bool _isDefect = false;
  110. //计算速度用,暂停时停止计数
  111. private Stopwatch pStopWatch = new Stopwatch();
  112. //计算速度用,计算实时速度
  113. private Stopwatch pRunSpeedWatch = new Stopwatch();
  114. private object lock_defectPuase = new object();
  115. /// <summary>
  116. /// 二次判定缺陷
  117. /// </summary>
  118. private List<DefectInfo> defectPuaseList = new List<DefectInfo>();
  119. /// <summary>
  120. ///
  121. /// </summary>
  122. private ConcurrentDictionary<int, Mat> defectPuaseImgList = new ConcurrentDictionary<int, Mat>();
  123. private object lock_defectDB = new object();
  124. /// <summary>
  125. /// 需要打标缺陷
  126. /// </summary>
  127. private List<DefectInfo> defectDBList = new List<DefectInfo>();
  128. //实时速度
  129. private double ActiveSpeed = 0;
  130. //实时位置
  131. private double ActiveDis = 0;
  132. //图片队列
  133. private int listCntMax = 60;
  134. private int Cam1Cnt = 0;
  135. private int Cam2Cnt = 0;
  136. int _marginWidth1 = 0;
  137. int _marginWidth2 = 0;
  138. /// <summary>
  139. /// 界面二次判定开启
  140. /// </summary>
  141. private bool DefectPauseForUser = true;
  142. /// <summary>
  143. /// 界面打标开启
  144. /// </summary>
  145. private bool DefectDBForUser = true;
  146. /// <summary>
  147. /// 第一次计米启用
  148. /// </summary>
  149. private bool JmFtStart = false;
  150. /// <summary>
  151. /// 界面光源值
  152. /// </summary>
  153. private int FrmLightValue = 0;
  154. #region 处理类型
  155. private class ScanPhotoInfo
  156. {
  157. /// <summary>
  158. ///
  159. /// </summary>
  160. /// <param name="_devIndex"></param>
  161. /// <param name="_photoIndex">1-n 第1张会把1改为0</param>
  162. /// <param name="_path"></param>
  163. public ScanPhotoInfo(int _devIndex, int _photoIndex, string _path)
  164. {
  165. devIndex = _devIndex;
  166. photoIndex = _photoIndex;
  167. path = _path;
  168. }
  169. public ScanPhotoInfo(int _devIndex, int _photoIndex, Mat _mat, double dis = 0)
  170. {
  171. devIndex = _devIndex;
  172. photoIndex = _photoIndex;
  173. mat = _mat;
  174. CurrDis = dis;
  175. }
  176. public int devIndex { get; set; }
  177. /// <summary>
  178. /// 0-n
  179. /// </summary>
  180. public int photoIndex { get; set; }
  181. public string path { get; set; }
  182. public Mat mat { get; set; }
  183. public double CurrDis { get; set; }
  184. }
  185. #endregion
  186. private ConcurrentQueue<ScanPhotoInfo> _matList1 = new ConcurrentQueue<ScanPhotoInfo>();
  187. private ConcurrentQueue<ScanPhotoInfo> _matList2 = new ConcurrentQueue<ScanPhotoInfo>();
  188. private Service.ProductService PdtService = new Service.ProductService();
  189. private Service.RecordsService RecordService = new Service.RecordsService();
  190. private bool _isOpenIO;
  191. private bool _isHaveImgL;
  192. private bool _isHaveImgR;
  193. #endregion
  194. #region 公开字段
  195. private bool _isInit;
  196. /// <summary>
  197. /// 是否初始化完成
  198. /// </summary>
  199. public bool IsInit { get { return _isInit; } }
  200. private bool _isRuning;
  201. /// <summary>
  202. /// 设备正在运行
  203. /// </summary>
  204. public bool IsRuning { get { return _isRuning; } }
  205. private bool _isAuto;
  206. /// <summary>
  207. /// 设备正在自动化流程中
  208. /// </summary>
  209. public bool IsAuto { get { return _isAuto; } }
  210. #endregion
  211. #region 私有流程
  212. //主流程
  213. private Thread _mainThread;
  214. private Thread _Cam1Thread;
  215. private Thread _Cam2Thread;
  216. private Thread _SpeedThread;
  217. private Thread _SaveImgThread;
  218. private CancellationTokenSource _cts;
  219. private Form _FatherFrm;
  220. private object _lockOpenCV = new object();
  221. #endregion
  222. #region 云端
  223. //局域网云端
  224. private bool init_Cloud;
  225. private CloudMgr cloudMgr;
  226. private int DailyOutput;
  227. #endregion
  228. private SysMgr()
  229. {
  230. _isInit = false;
  231. _isRuning = false;
  232. _isAuto = false;
  233. statusMgr = StatusMgr.Instance;
  234. confMgr = ConfMgr.Instance;
  235. userMgr = new UserMgr(statusMgr.MySqlIP);
  236. _cts = new CancellationTokenSource();
  237. init_Cloud = false;
  238. cloudMgr = new CloudMgr();
  239. DailyOutput = 0;
  240. Service.InitDB.ConnectionString = confMgr.DBConStr;
  241. PdtService = new Service.ProductService();
  242. RecordService = new Service.RecordsService();
  243. }
  244. #region 本地云上传
  245. /// <summary>
  246. /// 上传当日产量
  247. /// </summary>
  248. private void SendDailyOutput()
  249. {
  250. //开启云端
  251. if (init_Cloud)
  252. {
  253. try
  254. {
  255. if (!cloudMgr.SendTopic("device/attributes", $"{{ \"DailyOutput\": \"{DailyOutput}\"}}"))
  256. Log("云端", $"上传失败", WarningEnum.Low);
  257. }
  258. catch (Exception e)
  259. {
  260. Log("云端", $"上传失败:{e.Message}", WarningEnum.Low);
  261. }
  262. }
  263. }
  264. /// <summary>
  265. /// 上传正常状态
  266. /// </summary>
  267. public void SendStatus()
  268. {
  269. //开启云端
  270. if (init_Cloud)
  271. {
  272. //上传报警状态和信息
  273. string statusStr = "正常";
  274. switch (StatusMgr.Status)
  275. {
  276. case SystemStsEnum.Manual:
  277. statusStr = "人工操作";
  278. break;
  279. case SystemStsEnum.Standby:
  280. statusStr = "正常待机";
  281. break;
  282. case SystemStsEnum.Initial:
  283. statusStr = "初始化";
  284. break;
  285. case SystemStsEnum.Auto:
  286. statusStr = "自动运行";
  287. break;
  288. case SystemStsEnum.Pause:
  289. statusStr = "自动暂停";
  290. break;
  291. case SystemStsEnum.SetParams:
  292. statusStr = "参数设置";
  293. break;
  294. case SystemStsEnum.Debug:
  295. statusStr = "调试";
  296. break;
  297. case SystemStsEnum.Warning:
  298. statusStr = "系统报警";
  299. break;
  300. case SystemStsEnum.Bootload:
  301. statusStr = "Bootload";
  302. break;
  303. default:
  304. statusStr = "未知";
  305. break;
  306. }
  307. try
  308. {
  309. if (!cloudMgr.SendTopic("device/attributes", $"{{\"status\": \"{statusStr}\", \"alm\": \"无报警信息\", " +
  310. $"\"name\": \"{confMgr.SysConfigParams.CloudThisName}\", \"DailyOutput\": \"{DailyOutput}\"}}"))
  311. Log("云端", $"上传失败", WarningEnum.Low);
  312. }
  313. catch (Exception e)
  314. {
  315. Log("云端", $"上传失败:{e.Message}", WarningEnum.Low);
  316. }
  317. }
  318. }
  319. #endregion
  320. #region 用户+登入+管理
  321. /// <summary>
  322. /// 登入
  323. /// </summary>
  324. /// <returns></returns>
  325. public bool LoginSystem()
  326. {
  327. return userMgr.UserLoginDialog();
  328. }
  329. /// <summary>
  330. /// 用户权限
  331. /// </summary>
  332. public void UserPermissiomMgr()
  333. {
  334. userMgr.RightManageDialog();
  335. }
  336. /// <summary>
  337. /// 用户管理
  338. /// </summary>
  339. public void UserListMgr()
  340. {
  341. userMgr.UserManagerDialog();
  342. }
  343. #endregion
  344. #region 系统初始化&&运行
  345. /// <summary>
  346. /// 系统初始化
  347. /// </summary>
  348. /// <returns></returns>
  349. public bool Initial()
  350. {
  351. try
  352. {
  353. bool ret = false;
  354. string err = "";
  355. ret = confMgr.LoadSystemConfig();
  356. //根据llog路径,开始记录日志
  357. if (!Directory.Exists(confMgr.SysConfigParams.LogPath))
  358. throw new Exception("日志路径不存在");
  359. statusMgr.StartLog(confMgr.SysConfigParams.LogPath);
  360. InitLog("系统开始初始化...");
  361. //Thread.Sleep(200);
  362. int minWorker, minIOC;
  363. ThreadPool.GetMinThreads(out minWorker, out minIOC);
  364. bool trt = ThreadPool.SetMinThreads(25, minIOC);
  365. // 加载系统配置
  366. InitLog("加载系统参数...");
  367. //ret = confMgr.LoadSystemConfig();
  368. if (!ret)
  369. {
  370. throw new Exception("系统参数加载失败...");
  371. }
  372. InitLog("系统参数加载完成!");
  373. //根据llog路径,开始记录日志
  374. //if(!Directory.Exists(confMgr.SysConfigParams.LogPath))
  375. // throw new Exception("日志路径不存在");
  376. //statusMgr.StartLog(confMgr.SysConfigParams.LogPath);
  377. statusMgr.GotoInitial();
  378. SendStatus();
  379. //Thread.Sleep(200);
  380. // 硬件初始化
  381. if (!InitAllDev())
  382. {
  383. throw new Exception("硬件初始化失败...");
  384. }
  385. InitLog("硬件初始化完成!");
  386. // 加载硬件配置
  387. InitLog("加载硬件驱动参数...");
  388. if (!LoadDevConfig())
  389. {
  390. throw new Exception("加载硬件驱动参数失败...");
  391. }
  392. InitLog("加载硬件驱动参数完成!");
  393. //Thread.Sleep(200);
  394. // 处理运行
  395. InitLog("AI算法核心初始化...");
  396. defectLib = new DefectLib();
  397. if (!defectLib.start())
  398. throw new Exception("外观检测核心初始化失败...");
  399. InitLog("AI算法核心初始化完成!");
  400. LedReady();
  401. //初始化成功
  402. _isInit = true;
  403. statusMgr.GotoNormalStandby();
  404. SendStatus();
  405. OnInitRuning(new InitEventArgs("系统初始化完成...", this.IsInit));
  406. Run();
  407. return ret;
  408. }
  409. catch (Exception ex)
  410. {
  411. InitLog(ex.Message, "初始化", WarningEnum.High);
  412. InitLog("系统初始化失败!", "初始化", WarningEnum.High);
  413. //statusMgr.GotoWarning(MaiMuControl.Device.WarningEnum.High, "初始化", ex.Message);
  414. return false;
  415. }
  416. }
  417. /// <summary>
  418. /// 初始化图像处理报警
  419. /// </summary>
  420. /// <returns></returns>
  421. public bool InitDefectEvent()
  422. {
  423. if (defectLib != null)
  424. {
  425. defectLib.WarningEvent = (warning, msg) =>
  426. {
  427. Log("缺陷检测", msg, warning);
  428. };
  429. return true;
  430. }
  431. return false;
  432. }
  433. public bool InitCloudConnect()
  434. {
  435. if (confMgr.SysConfigParams.OpenCloud)
  436. {
  437. if (cloudMgr.ConnectCloud(confMgr.SysConfigParams.CloudServerIP, confMgr.SysConfigParams.CloudServerPort,
  438. confMgr.SysConfigParams.CloudUser, confMgr.SysConfigParams.CloudPassword))
  439. {
  440. init_Cloud = true;
  441. Log("云端数据", "开启云端连接");
  442. return true;
  443. }
  444. Log("云端数据", "云端连接失败!", WarningEnum.Low);
  445. return false;
  446. }
  447. return true;
  448. }
  449. /// <summary>
  450. /// 运行主线程
  451. /// </summary>
  452. private void Run()
  453. {
  454. _mainThread = new Thread(() =>
  455. {
  456. MainThreadFunction();
  457. });
  458. _mainThread.IsBackground = true;
  459. _mainThread.Start();
  460. #if Online_One
  461. #else
  462. _Cam1Thread = new Thread(() =>
  463. {
  464. Cam1ThreadFunction();
  465. });
  466. _Cam1Thread.IsBackground = true;
  467. _Cam1Thread.Start();
  468. _Cam2Thread = new Thread(() =>
  469. {
  470. Cam2ThreadFunction();
  471. });
  472. _Cam2Thread.IsBackground = true;
  473. _Cam2Thread.Start();
  474. #endif
  475. _SpeedThread = new Thread(() =>
  476. {
  477. GetLenAndSpd();
  478. });
  479. _SpeedThread.IsBackground = true;
  480. _SpeedThread.Start();
  481. _SaveImgThread = new Thread(() =>
  482. {
  483. SaveImgThreadFunction();
  484. });
  485. _SaveImgThread.IsBackground = true;
  486. _SaveImgThread.Start();
  487. }
  488. #endregion
  489. #region 二次判断开关
  490. public void SetDefectPause(bool val)
  491. {
  492. DefectPauseForUser = val;
  493. }
  494. public bool GetDefectPause()
  495. {
  496. return DefectPauseForUser;
  497. }
  498. #endregion
  499. #region 打标开关
  500. public void SetDefectDB(bool val)
  501. {
  502. DefectDBForUser = val;
  503. }
  504. public bool GetDefectDB()
  505. {
  506. return DefectDBForUser;
  507. }
  508. #endregion
  509. #region 界面光源设置
  510. public void SetLightValue(int val)
  511. {
  512. FrmLightValue = val;
  513. if(IsInit)
  514. lightDev.SetLightDigitalValue(1, val);
  515. }
  516. #endregion
  517. #region 计米器控制
  518. /// <summary>
  519. /// 计米器清空
  520. /// </summary>
  521. private void ClearLengthCount()
  522. {
  523. if (confMgr.SysConfigParams.OpenLengthCount)
  524. {
  525. byte[] clearData = new byte[] { 0x01, 0x06, 0x00, 0x00, 0x00, 0x01, 0x48, 0x0a };
  526. lengthCounter.Write(clearData, 0, 8);
  527. //Thread.Sleep(100);
  528. Thread.Sleep(10);
  529. byte[] recv = new byte[64];
  530. //string recvdata = serialPort.ReadLine();
  531. //recv = recvdata.ToBytes();
  532. int readCnt = lengthCounter.BytesToRead;
  533. lengthCounter.Read(recv, 0, readCnt);
  534. }
  535. }
  536. /// <summary>
  537. /// 获取计米数据
  538. /// </summary>
  539. /// <returns></returns>
  540. private double GetLength()
  541. {
  542. //bool isFile = true;
  543. double length = -1;
  544. bool GetData = false;
  545. if (lengthCounter.IsOpen)
  546. {
  547. byte[] data = new byte[] { 0x01, 0x03, 0x00, 0x21, 0x00, 0x02, 0x94, 0x01 };
  548. lengthCounter.Write(data, 0, 8);
  549. Thread.Sleep(10);
  550. byte[] recv = new byte[64];
  551. //string recvdata = serialPort.ReadLine();
  552. //recv = recvdata.ToBytes();
  553. int readCnt = lengthCounter.BytesToRead;
  554. lengthCounter.Read(recv, 0, readCnt);
  555. byte[] bytes = new byte[4];
  556. for (int i = 0; i < readCnt; i++)
  557. {
  558. if (recv[i] == 0x01 && recv[i + 1] == 0x03 && recv[i + 2] == 0x04)
  559. {
  560. bytes[0] = recv[i + 3];
  561. bytes[1] = recv[i + 4];
  562. bytes[2] = recv[i + 5];
  563. bytes[3] = recv[i + 6];
  564. GetData = true;
  565. }
  566. }
  567. if (GetData)
  568. {
  569. if (BitConverter.IsLittleEndian)
  570. Array.Reverse(bytes);
  571. int spddata = BitConverter.ToInt32(bytes, 0);
  572. length = spddata / 100.0;
  573. //if (isFile)
  574. // length = -length;
  575. }
  576. if (length > 10000)
  577. return -1;
  578. }
  579. return length;
  580. }
  581. #endregion
  582. #region 后台
  583. #region 计米器位置和速度
  584. private object LockSpd = new object();
  585. private object LockDis = new object();
  586. private void SetSpd(double spd)
  587. {
  588. lock (LockSpd)
  589. {
  590. ActiveSpeed = spd;
  591. }
  592. }
  593. private double GetSpd()
  594. {
  595. double spd;
  596. lock (LockSpd)
  597. {
  598. spd = ActiveSpeed;
  599. }
  600. return spd;
  601. }
  602. private void SetDis(double dis)
  603. {
  604. lock (LockDis)
  605. {
  606. ActiveDis = dis;
  607. }
  608. }
  609. private double GetDis()
  610. {
  611. double dis;
  612. lock (LockDis)
  613. {
  614. dis = ActiveDis;
  615. }
  616. return dis;
  617. }
  618. #endregion
  619. #region 中断
  620. /// <summary>
  621. /// 中断工序运行
  622. /// </summary>
  623. /// <returns></returns>
  624. private bool isBreakProcessRun()
  625. {
  626. return statusMgr.Status == SystemStsEnum.Pause || statusMgr.Warning == WarningEnum.High;
  627. }
  628. #endregion
  629. #region 长度与速度流程
  630. /// <summary>
  631. /// 获取速度和长度
  632. /// </summary>
  633. private void GetLenAndSpd()
  634. {
  635. double stl = 0; //计米起始位置
  636. double etl = 0; //计米结束位置
  637. double spl = 0; //计算速度计米位置
  638. double yqjimi = 0; //计米长度
  639. double cehouDis = 0;//测厚位置记录
  640. double UseTime = 1;
  641. double preSpd = 0;//上次速度,防止速度出差
  642. double rioSpd = 0.3;//过冲
  643. while (true)
  644. {
  645. int spdcnt = 0;
  646. try
  647. {
  648. if (_cts.IsCancellationRequested)
  649. break;
  650. if (IsRuning)
  651. {
  652. ////暂停开始
  653. //stopWatch.Start();
  654. do
  655. {
  656. #if Online
  657. if (currKey > 0)
  658. {
  659. Records curRecord = Hashtable.Synchronized(htTask)[currKey] as Records;
  660. #region 实时速度
  661. if (confMgr.SysConfigParams.OpenLengthCount)
  662. {
  663. double length = GetLength();
  664. if (length >= 0)
  665. {
  666. if (!JmFtStart)
  667. {
  668. //第一次记录起始数据
  669. stl = 0;
  670. spl = 0;
  671. cehouDis = 0;
  672. JmFtStart = true;
  673. pRunSpeedWatch.Restart();
  674. }
  675. else
  676. {
  677. //1s计算一次实时速度
  678. double dt = pRunSpeedWatch.ElapsedMilliseconds;
  679. if (dt / 1000.0d > UseTime)
  680. {
  681. double spddis = Math.Abs(length - spl);
  682. spl = length;
  683. double runOnePicTime = dt / 1000.0d /( 60.0d);//总时间 分
  684. double spd = Math.Round(spddis / runOnePicTime, 2);
  685. //if (spd !=0&&((Math.Abs(spd - preSpd) / preSpd) > rioSpd))
  686. //{
  687. // spd = (Math.Abs(spd - preSpd))/4 + preSpd;
  688. //}
  689. preSpd = spd;
  690. SetSpd(spd);
  691. if (spdcnt > 2)
  692. {
  693. Log($"计米对比", $"计米器距离{Math.Round(spddis,2)},计米速度{Math.Round(spd,2)},计米时间{Math.Round(runOnePicTime,4)}", WarningEnum.Normal, false);
  694. spdcnt = 0;
  695. }
  696. spdcnt++;
  697. //重新计时
  698. pRunSpeedWatch.Restart();
  699. }
  700. etl = length;//记录当前读数
  701. yqjimi = Math.Round((etl - stl) / 1.00, 2); //记录长度
  702. SetDis(yqjimi);
  703. }
  704. lock (lockCurrKey)
  705. {
  706. curRecord.Len = yqjimi;
  707. curRecord.TimeLen = pStopWatch.ElapsedMilliseconds / 1000.0d / 60.0d;//总时间 分
  708. }
  709. double tRunSpd = GetSpd();//1s计算的实时速度
  710. //显示平均速度
  711. OnAutoRuning(new RunEventArgs(yqjimi, tRunSpd));
  712. #region 处理2次判定
  713. //处理2次判定
  714. double aveSpd = Math.Round(yqjimi / (pStopWatch.ElapsedMilliseconds / 1000.0d / (60.0d)), 2);
  715. double StopDecRunDis = tRunSpd / 60.0 * confMgr.SysConfigParams.StopDecTime / 2;
  716. double atcDis = (confMgr.SysConfigParams.StopLookDis - StopDecRunDis);
  717. //计米器判断暂停:瑕疵二次判断 存在问题
  718. if (confMgr.SysConfigParams.OpenLengthCountStop && DefectPauseForUser && defectPuaseList.Count > 0)
  719. {
  720. if ((yqjimi - atcDis) > (defectPuaseList[0].Y / 100))
  721. {
  722. //if ((yqjimi - atcDis) < (defectPuaseList[0].Y / 100 + 1))
  723. {
  724. Log($"二次判断", $"计米器{yqjimi},瑕疵位置{defectPuaseList[0].Y / 100},停车距离{confMgr.SysConfigParams.StopLookDis}m,停车减速时间{confMgr.SysConfigParams.StopDecTime}s,减速位移{StopDecRunDis},实际停车距离{atcDis},实时速度{tRunSpd},匀速{aveSpd}", WarningEnum.Normal, false);
  725. List<DefectInfo> lstEditDefect0 = defectPuaseList.Where(m => m.PhotoIndex == defectPuaseList[0].PhotoIndex).ToList();
  726. Log($"二次判断", $"(图像{defectPuaseList[0].PhotoIndex})已达观察台,瑕疵二次判断=》({string.Join(",", lstEditDefect0.Select(m => m.Code).ToArray())})是否包含在({string.Join(",", curRecord.ProductInfo.DefectPauseOption.ToArray())})中。", WarningEnum.Normal, false);
  727. //瑕疵选项过滤
  728. if (curRecord.ProductInfo.DefectPauseOption.Count == 0 || lstEditDefect0.Where(x => curRecord.ProductInfo.DefectPauseOption.Contains(x.Code)).Count() > 0)
  729. {
  730. Log($"二次判断", $"(图像{defectPuaseList[0].PhotoIndex})需瑕疵二次判断,已达观察台,进入暂停。", WarningEnum.Normal, false);
  731. if (lstEditDefect0.Where(x => DefectItemsPuaseNameList.Contains(x.Name)).Count() > 0)
  732. {
  733. Stop();
  734. //获取完整数据
  735. Thread.Sleep(500);
  736. var lstEditDefect = defectPuaseList.Where(m => m.PhotoIndex == defectPuaseList[0].PhotoIndex).ToList();
  737. #region 二级界面
  738. int liPhotoIndex = defectPuaseList[0].PhotoIndex;
  739. #region 加载界面
  740. if (defectPuaseImgList.ContainsKey(liPhotoIndex))
  741. {
  742. var pimage = (Bitmap)defectPuaseImgList[liPhotoIndex].ToBitmap().Clone();
  743. var pmat = defectPuaseImgList[liPhotoIndex].Clone();
  744. Task.Run(() =>
  745. {
  746. int liDefectCount = lstEditDefect.Count;
  747. ImageShowFrm frmDefect = new ImageShowFrm(liPhotoIndex, lstEditDefect, pimage);
  748. //frmDefect.Show();
  749. if (frmDefect.ShowDialog() == DialogResult.OK)
  750. {
  751. SysMgr.Instance.DelDefectEdit(curRecord, frmDefect.lstDel);
  752. OnAutoRuning(new RunEventArgs(liPhotoIndex, lstEditDefect, curRecord, pmat, frmDefect.lstDel));
  753. //double len = (double)this.lblLen.Tag;
  754. //this.reDrawDefectPoints(curRecord.DefectInfoList, new double[] { 0, Math.Round(curRecord.FaceWidthMax + 0.005f, 2) }, new double[] { 0, len });
  755. Log($"二次检测", $"本次忽略{frmDefect.lstDel.Count}个瑕疵,本张图由{liDefectCount} -> {lstEditDefect.Count},总数{curRecord.DefectInfoList.Count}");
  756. }
  757. else
  758. {
  759. OnAutoRuning(new RunEventArgs(liPhotoIndex, lstEditDefect, curRecord, pmat, null));
  760. }
  761. });
  762. }
  763. else
  764. Log($"二次检测", $"本次图像已检测完成");
  765. #endregion
  766. //OnAutoRuning(new RunEventArgs(liPhotoIndex, lstEditDefect, curRecord, defectPuaseImgList[liPhotoIndex]));
  767. #endregion
  768. }
  769. }
  770. Log($"二次判断删除", $"{defectPuaseList[0].PhotoIndex}-{testCnt}", WarningEnum.Normal, false);
  771. lstEditDefect0 = defectPuaseList.Where(m => m.PhotoIndex == defectPuaseList[0].PhotoIndex).ToList();
  772. if (lstEditDefect0.Count > 0 && defectPuaseImgList.Count > 0)
  773. {
  774. Mat mt;
  775. defectPuaseImgList.TryRemove(lstEditDefect0[0].PhotoIndex, out mt);
  776. }
  777. //foreach (var item in lstEditDefect0)
  778. {
  779. lock (lock_defectPuase)
  780. {
  781. defectPuaseList.RemoveAll(m => m.PhotoIndex == defectPuaseList[0].PhotoIndex);
  782. //defectPuaseList.Remove(item);
  783. }
  784. }
  785. }
  786. //else
  787. //{
  788. // Log($"二次判断", $"速度过快,超过展示位置!实时速度{tRunSpd},{defectPuaseList[0].PhotoIndex}-{testCnt}", WarningEnum.Low, true);
  789. //}
  790. }
  791. }
  792. //计米器判定打标
  793. if(DefectDBForUser && defectDBList.Count >0)
  794. {
  795. //判断是否开启打标
  796. if((yqjimi - defectDBList[0].CurrDis + (defectDBList[0].PicY / 100) - confMgr.SysConfigParams.CamToDBDis) >= 0)
  797. {
  798. Log($"打标", $"计米器{yqjimi},瑕疵位置{defectDBList[0].PicY / 100},拍照位置{defectDBList[0].CurrDis},打标机距离{confMgr.SysConfigParams.StopLookDis}m,", WarningEnum.Normal, false);
  799. StartDB();
  800. Log($"打标判断删除", $"{defectDBList[0].PhotoIndex}-{defectDBList[0].Name}", WarningEnum.Normal, false);
  801. defectDBList.RemoveAt(0);
  802. }
  803. }
  804. #endregion
  805. }
  806. }
  807. #endregion
  808. #endif
  809. #region 堆积显示
  810. OnAutoRuning(new RunEventArgs(_matList1.Count, _matList2.Count, defectLib.GetDefectInfo()));
  811. //System.GC.Collect();
  812. #endregion
  813. #if Online
  814. lock (lockCurrKey)
  815. {
  816. #region 换卷长度提示
  817. if (confMgr.SysConfigParams.OpenLengthCount)
  818. {
  819. if (curRecord.ProductInfo.residueWarnningLen > 0 && yqjimi > curRecord.ProductInfo.residueWarnningLen)
  820. {
  821. Log($"告警", $"已经达到换卷长度最大值{curRecord.ProductInfo.residueWarnningLen}-当前长度{yqjimi}-", WarningEnum.High);
  822. }
  823. }
  824. #endregion
  825. #region 测厚停止
  826. if (confMgr.SysConfigParams.OpenLengthCount && curRecord.ProductInfo.OpenThicknessDetection)
  827. {
  828. if (curRecord.ProductInfo.ThicknessDetectionStopDis > 0 && (yqjimi - cehouDis) > curRecord.ProductInfo.ThicknessDetectionStopDis)
  829. {
  830. Stop();
  831. Log($"测厚提示", $"已经达到测厚位置{curRecord.ProductInfo.ThicknessDetectionStopDis}-当前前进长度{(yqjimi - cehouDis)}-", WarningEnum.High);
  832. }
  833. }
  834. #endregion
  835. }
  836. }
  837. #endif
  838. Thread.Sleep(200);
  839. } while (!isBreakProcessRun());
  840. //暂停中断
  841. //stopWatch.Stop();
  842. //pStopWatch.Stop();
  843. //_isRuning = false;
  844. }
  845. Thread.Sleep(10);
  846. }
  847. catch (Exception e)
  848. {
  849. _isRuning = false;
  850. Log("运行报警", "计米流程运行出错:" + e.Message + "\n", WarningEnum.High);
  851. }
  852. }
  853. }
  854. #endregion
  855. #region 相机线程1 && 二次判定
  856. /// <summary>
  857. /// 相机1采图预处理
  858. /// </summary>
  859. private void Cam1ThreadFunction()
  860. {
  861. int errStep = 0;
  862. #if Online
  863. #else
  864. string imgfilePath = "D:\\CPL\\img\\L1.bmp";
  865. Mat timg = new Mat(imgfilePath);
  866. timg = timg.Flip(FlipMode.XY);
  867. #endif
  868. while (true)
  869. {
  870. try
  871. {
  872. if (_cts.IsCancellationRequested)
  873. break;
  874. if (IsRuning)
  875. {
  876. ////暂停开始
  877. //stopWatch.Start();
  878. do
  879. {
  880. #region 实时采图
  881. #if Online
  882. //采集图片
  883. AcquisitionMat acq = _LinecamDev1.GetFrames(100);
  884. if (acq.GrabStatus == "GrabPass")
  885. {
  886. #else
  887. Thread.Sleep(2500);
  888. AcquisitionMat acq = new AcquisitionMat();
  889. {
  890. acq.GrabStatus = "GrabPass";
  891. acq.Image = timg.Clone();
  892. Log($"图像预处理", $"模拟相机1-{Cam1Cnt}", WarningEnum.Normal, true);
  893. }
  894. if (acq.GrabStatus == "GrabPass")
  895. {
  896. #endif
  897. //专用二次判断处理
  898. #if true
  899. #region 处理2次判定
  900. if (!confMgr.SysConfigParams.OpenLengthCountStop)
  901. {
  902. //处理2次判定
  903. //暂停:瑕疵二次判断
  904. if (DefectPauseForUser )
  905. {
  906. errStep = 11;
  907. Records curRecord = Hashtable.Synchronized(htTask)[currKey] as Records;
  908. int liPhotoIndex = Cam1Cnt - confMgr.SysConfigParams.StopImageCnt;
  909. #if false
  910. var havePause = curRecord.dicPhoto_Defect.Where(x => x.Key <= liPhotoIndex && x.Value == true);
  911. if(havePause != null)
  912. {
  913. foreach (var item in havePause)
  914. {
  915. liPhotoIndex = item.Key;
  916. break;
  917. }
  918. }
  919. #endif
  920. //Log($"二次判断2", $"图像{scanPhotos0.photoIndex} {liPhotoIndex}={scanPhotos0.photoIndex}-{confMgr.SysConfigParams.StopImageCnt};{JsonConvert.SerializeObject(curRecord.dicPhoto_Defect)}", WarningEnum.Normal, false);
  921. if (liPhotoIndex >= 0 && curRecord.dicPhoto_Defect.ContainsKey(liPhotoIndex) && curRecord.dicPhoto_Defect[liPhotoIndex] )
  922. {
  923. if (defectPuaseList.Count > 0)
  924. {
  925. errStep = 12;
  926. List<DefectInfo> lstEditDefect = defectPuaseList.Where(m => m.PhotoIndex == liPhotoIndex).ToList();
  927. Log($"二次判断2", $"(图像{liPhotoIndex})已达观察台,瑕疵二次判断=》({string.Join(",", lstEditDefect.Select(m => m.Code).ToArray())})是否包含在({string.Join(",", curRecord.ProductInfo.DefectPauseOption.ToArray())})中。", WarningEnum.Normal, false);
  928. //瑕疵选项过滤
  929. if (curRecord.ProductInfo.DefectPauseOption.Count == 0 || lstEditDefect.Where(x => curRecord.ProductInfo.DefectPauseOption.Contains(x.Code)).Count() > 0)
  930. {
  931. Log($"二次判断2", $"(图像{liPhotoIndex})需瑕疵二次判断,已达观察台,进入暂停。速度:{GetSpd()}");
  932. // if (lstEditDefect.Where(x => x.Code == "jietou").Count() > 0)
  933. if (lstEditDefect.Where(x => DefectItemsPuaseNameList.Contains(x.Name)).Count() > 0)
  934. {
  935. Stop();
  936. //获取完整数据
  937. Thread.Sleep(500);
  938. lstEditDefect = defectPuaseList.Where(m => m.PhotoIndex == liPhotoIndex).ToList();
  939. //获取完整数据
  940. #region 二级界面
  941. #region 加载界面
  942. if (defectPuaseImgList.ContainsKey(liPhotoIndex))
  943. {
  944. var pmat = defectPuaseImgList[liPhotoIndex].Clone();
  945. //OnAutoRuning(new RunEventArgs(liPhotoIndex, lstEditDefect, curRecord, pmat));
  946. #if true
  947. var pimage = (Bitmap)defectPuaseImgList[liPhotoIndex].ToBitmap().Clone();
  948. Task.Run(() =>
  949. {
  950. int liDefectCount = lstEditDefect.Count;
  951. ImageShowFrm frmDefect = new ImageShowFrm(liPhotoIndex, lstEditDefect, pimage);
  952. //if (frmDefect.ShowDialog(_FatherFrm) == DialogResult.OK)
  953. if (frmDefect.ShowDialog() == DialogResult.OK)
  954. {
  955. SysMgr.Instance.DelDefectEdit(curRecord, frmDefect.lstDel);
  956. OnAutoRuning(new RunEventArgs(liPhotoIndex, lstEditDefect, curRecord, pmat, frmDefect.lstDel));
  957. Log($"二次检测2", $"本次忽略{frmDefect.lstDel.Count}个瑕疵,本张图由{liDefectCount} -> {lstEditDefect.Count},总数{curRecord.DefectInfoList.Count}");
  958. }
  959. else
  960. {
  961. OnAutoRuning(new RunEventArgs(liPhotoIndex, lstEditDefect, curRecord, pmat, null));
  962. }
  963. });
  964. #endif
  965. }
  966. else
  967. Log($"二次检测2", $"本次图像已检测完成");
  968. #endregion
  969. //OnAutoRuning(new RunEventArgs(liPhotoIndex, lstEditDefect, curRecord, defectPuaseImgList[liPhotoIndex]));
  970. #endregion
  971. }
  972. errStep = 18;
  973. }
  974. Log($"二次判断删除", $"{liPhotoIndex}-{testCnt}", WarningEnum.Normal, false);
  975. lstEditDefect = defectPuaseList.Where(m => m.PhotoIndex == liPhotoIndex).ToList();
  976. if (lstEditDefect.Count > 0 && defectPuaseImgList.Count > 0)
  977. {
  978. Mat mt;
  979. defectPuaseImgList.TryRemove(lstEditDefect[0].PhotoIndex, out mt);
  980. }
  981. //foreach (var item in lstEditDefect)
  982. {
  983. lock (lock_defectPuase)
  984. {
  985. defectPuaseList.RemoveAll(m => m.PhotoIndex == liPhotoIndex);
  986. //defectPuaseList.Remove(item);
  987. }
  988. }
  989. }
  990. else
  991. Log($"二次判断2", $"(图像{liPhotoIndex})-缺陷未获得", WarningEnum.Low, false);
  992. #if false
  993. curRecord.dicPhoto_Defect.TryUpdate(liPhotoIndex, false, true);
  994. #endif
  995. }
  996. //else
  997. // Log($"二次判断2", $"(图像{liPhotoIndex})-处理未跟上", WarningEnum.Low, false);
  998. }
  999. //time += $"->处理2次判定({stopWatch.ElapsedMilliseconds})";
  1000. }
  1001. #endregion
  1002. #endif
  1003. //预处理
  1004. Stopwatch stopWatch = new Stopwatch();
  1005. //Log($"图像预处理", $"相机1-{Cam1Cnt}", WarningEnum.Normal, false);
  1006. string time = "";
  1007. stopWatch.Start();
  1008. Mat img = acq.Image.Clone();
  1009. //图像镜像
  1010. if (confMgr.SysConfigParams.Cam1_flipX && confMgr.SysConfigParams.Cam1_flipY)
  1011. {
  1012. img = img.Flip(FlipMode.XY);
  1013. //Cv2.Flip(img, img, FlipMode.XY);//翻转
  1014. }
  1015. else if (confMgr.SysConfigParams.Cam1_flipX)
  1016. {
  1017. img = img.Flip(FlipMode.X);
  1018. //Cv2.Flip(img, img, FlipMode.X);//翻转
  1019. }
  1020. else if (confMgr.SysConfigParams.Cam1_flipY)
  1021. {
  1022. img = img.Flip(FlipMode.Y);
  1023. //Cv2.Flip(img, img, FlipMode.Y);//翻转
  1024. }
  1025. time += $"->相机1翻转({stopWatch.ElapsedMilliseconds})";
  1026. //显示
  1027. //OnAutoRuning(new RunEventArgs(1, img));
  1028. //lock (_lockOpenCV)
  1029. {
  1030. //存在数据队列
  1031. if (currKey != 0 || htTask.ContainsKey(currKey))
  1032. {
  1033. //保存图片
  1034. if (confMgr.SysConfigParams.CamImag.AutoSave && !string.IsNullOrEmpty(confMgr.SysConfigParams.CamImag.SavePath))
  1035. {
  1036. Records curRecord = Hashtable.Synchronized(htTask)[currKey] as Records;
  1037. string dirPath = Util.CreateSubDir(confMgr.SysConfigParams.CamImag.SavePath, new List<string> { $"{curRecord.BarCode}_{curRecord.BarCodeName}" });
  1038. //OpenCvSharp.Extensions.BitmapConverter.ToBitmap(img).Save($"{dirPath}Cam1-{Cam1Cnt}.bmp", ImageFormat.Bmp);
  1039. AddImageSave($"{dirPath}Cam1-{Cam1Cnt}.bmp", img);
  1040. }
  1041. if (_matList1.Count > listCntMax)
  1042. {
  1043. Log($"堆积过多", $"相机1-缓存{_matList1.Count}大于{listCntMax}", WarningEnum.High);
  1044. //_matList1.Dequeue();
  1045. System.GC.Collect();
  1046. }
  1047. Mat mat = img;
  1048. try
  1049. {
  1050. errStep = 1;
  1051. //反转+相机索引调换
  1052. //lock (_lockOpenCV)
  1053. {
  1054. //裁边,两侧和中间重合部分
  1055. if (confMgr.SysConfigParams.MidCoin > 0)//中间重合部分
  1056. {
  1057. errStep = 3;
  1058. int width = mat.Width - confMgr.SysConfigParams.MidCoin / 2;
  1059. mat = OpencvUtils.CutImage(mat, 0, 0, width, mat.Height);
  1060. time += $"->相机1-去重({stopWatch.ElapsedMilliseconds})";
  1061. }
  1062. }
  1063. errStep = 4;
  1064. //左裁边
  1065. int marginWidth0;
  1066. mat = OpencvUtils.getMaxInsetRect2(mat, true, confMgr.SysConfigParams.HolePx, out marginWidth0);
  1067. //存储裁边异常相机图 差异5cm
  1068. if (_marginWidth1 == 0)
  1069. _marginWidth1 = marginWidth0;
  1070. if (!confMgr.SysConfigParams.CamImag.AutoSave && Math.Abs(marginWidth0 - _marginWidth1) > (10 * confMgr.SysConfigParams.Cm2px_x) && !string.IsNullOrEmpty(confMgr.SysConfigParams.CamImag.SavePath))
  1071. {
  1072. Records curRecord = Hashtable.Synchronized(htTask)[currKey] as Records;
  1073. string dirPath = Util.CreateSubDir(confMgr.SysConfigParams.CamImag.SavePath, new List<string> { $"{curRecord.BarCode}_{curRecord.BarCodeName}" });
  1074. AddImageSave($"{dirPath}Cam1-{Cam1Cnt}.bmp", img);
  1075. Log($"图像预处理", $"(相机1-图像{Cam1Cnt})-裁边异常:{marginWidth0}-{_marginWidth1} 》 {10 * confMgr.SysConfigParams.Cm2px_x}", WarningEnum.Normal, false);
  1076. }
  1077. _marginWidth1 = marginWidth0;
  1078. errStep = 5;
  1079. time += $"->相机1裁边({stopWatch.ElapsedMilliseconds})";
  1080. Log($"图像预处理", $"(相机1-图像{Cam1Cnt})-左图去重后:{mat.Width}*{mat.Height}," + $"重复值:{confMgr.SysConfigParams.MidCoin / 2} + 时间{time}", WarningEnum.Normal, false);
  1081. //System.GC.Collect();
  1082. }
  1083. catch (Exception e)
  1084. {
  1085. Log($"图像处理", $"异常({errStep}):(相机1-图像{Cam1Cnt})-{e.Message}", WarningEnum.High);
  1086. }
  1087. //Log($"图像1入队列", $"相机1-{Cam1Cnt}", WarningEnum.Normal, false);
  1088. //Cv2.Flip(img, img, FlipMode.XY);//翻转
  1089. _matList1.Enqueue(new ScanPhotoInfo(0, Cam1Cnt++, mat.Clone()));
  1090. }
  1091. else
  1092. Log($"相机1", $"(图像)-未扫码,图像丢弃!", WarningEnum.Low);
  1093. }
  1094. }
  1095. #endregion
  1096. //System.GC.Collect();
  1097. Thread.Sleep(50);
  1098. } while (!isBreakProcessRun());
  1099. //暂停中断
  1100. //stopWatch.Stop();
  1101. pStopWatch.Stop();
  1102. //_isRuning = false;
  1103. }
  1104. else
  1105. {
  1106. //防止内存爆满
  1107. AcquisitionMat acq = _LinecamDev1.GetFrames(10);
  1108. }
  1109. Thread.Sleep(50);
  1110. }
  1111. catch (Exception e)
  1112. {
  1113. _isRuning = false;
  1114. Log("运行报警", $"相机1流程运行出错{errStep}:" + e.Message + "\n", WarningEnum.High);
  1115. }
  1116. }
  1117. }
  1118. #endregion
  1119. #region 相机线程2 && 图片位置
  1120. /// <summary>
  1121. /// 相机2采图预处理
  1122. /// </summary>
  1123. private void Cam2ThreadFunction()
  1124. {
  1125. #if Online
  1126. #else
  1127. string imgfilePath = "D:\\CPL\\img\\R1.bmp";
  1128. Mat timg = new Mat(imgfilePath);
  1129. timg = timg.Flip(FlipMode.XY);
  1130. #endif
  1131. while (true)
  1132. {
  1133. try
  1134. {
  1135. if (_cts.IsCancellationRequested)
  1136. break;
  1137. if (IsRuning)
  1138. {
  1139. ////暂停开始
  1140. //stopWatch.Start();
  1141. do
  1142. {
  1143. #region 实时采图
  1144. #if Online
  1145. //采集图片
  1146. AcquisitionMat acq = _LinecamDev2.GetFrames(10);
  1147. if (acq.GrabStatus == "GrabPass")
  1148. {
  1149. #else
  1150. Thread.Sleep(2500);
  1151. AcquisitionMat acq = new AcquisitionMat();
  1152. {
  1153. acq.GrabStatus = "GrabPass";
  1154. acq.Image = timg;
  1155. Log($"图像预处理", $"模拟相机2-{Cam2Cnt}", WarningEnum.Normal, true);
  1156. }
  1157. if (acq.GrabStatus == "GrabPass")
  1158. {
  1159. #endif
  1160. //获取图片成功,说明正好拍完照片,获取当前计米器位置
  1161. double picDis = GetDis();
  1162. Mat img = acq.Image.Clone();
  1163. //预处理
  1164. Stopwatch stopWatch = new Stopwatch();
  1165. //Log($"图像预处理", $"相机2-{Cam2Cnt}", WarningEnum.Normal, false);
  1166. string time = "";
  1167. stopWatch.Start();
  1168. //图像镜像
  1169. if (confMgr.SysConfigParams.Cam2_flipX && confMgr.SysConfigParams.Cam2_flipY)
  1170. {
  1171. img = img.Flip(FlipMode.XY);
  1172. //Cv2.Flip(img, img, FlipMode.XY);//翻转
  1173. }
  1174. else if (confMgr.SysConfigParams.Cam2_flipX)
  1175. {
  1176. img = img.Flip(FlipMode.X);
  1177. //Cv2.Flip(img, img, FlipMode.X);//翻转
  1178. }
  1179. else if (confMgr.SysConfigParams.Cam2_flipY)
  1180. {
  1181. img = img.Flip(FlipMode.Y);
  1182. //Cv2.Flip(img, img, FlipMode.Y);//翻转
  1183. }
  1184. time += $"->相机2翻转({stopWatch.ElapsedMilliseconds})";
  1185. //显示
  1186. //OnAutoRuning(new RunEventArgs(2, img));
  1187. //lock (_lockOpenCV)
  1188. {
  1189. //存在数据队列
  1190. if (currKey != 0 || htTask.ContainsKey(currKey))
  1191. {
  1192. //保存图片
  1193. if (confMgr.SysConfigParams.CamImag.AutoSave && !string.IsNullOrEmpty(confMgr.SysConfigParams.CamImag.SavePath))
  1194. {
  1195. Records curRecord = Hashtable.Synchronized(htTask)[currKey] as Records;
  1196. string dirPath = Util.CreateSubDir(confMgr.SysConfigParams.CamImag.SavePath, new List<string> { $"{curRecord.BarCode}_{curRecord.BarCodeName}" });
  1197. //OpenCvSharp.Extensions.BitmapConverter.ToBitmap(img).Save($"{dirPath}Cam2-{Cam2Cnt}.bmp", ImageFormat.Bmp);
  1198. AddImageSave($"{dirPath}Cam2-{Cam2Cnt}.bmp", img);
  1199. }
  1200. if (_matList2.Count > listCntMax)
  1201. {
  1202. Log($"堆积过多", $"相机2-缓存{_matList2.Count}大于{listCntMax}", WarningEnum.High);
  1203. //_matList2.Dequeue();
  1204. System.GC.Collect();
  1205. }
  1206. int errStep = 0;
  1207. Mat mat = img;
  1208. try
  1209. {
  1210. errStep = 1;
  1211. //反转+相机索引调换
  1212. //lock (_lockOpenCV)
  1213. {
  1214. //裁边,两侧和中间重合部分
  1215. if (confMgr.SysConfigParams.MidCoin > 0)//中间重合部分
  1216. {
  1217. errStep = 3;
  1218. int width = mat.Width - confMgr.SysConfigParams.MidCoin / 2;
  1219. mat = OpencvUtils.CutImage(mat, confMgr.SysConfigParams.MidCoin / 2, 0, width, mat.Height);
  1220. time += $"->相机2-去重({stopWatch.ElapsedMilliseconds})";
  1221. }
  1222. }
  1223. errStep = 4;
  1224. //右裁边
  1225. int marginWidth0;
  1226. mat = OpencvUtils.getMaxInsetRect2(mat, false, confMgr.SysConfigParams.HolePx, out marginWidth0);
  1227. //存储裁边异常相机图 差异5cm
  1228. if (_marginWidth2 == 0)
  1229. _marginWidth2 = marginWidth0;
  1230. if (!confMgr.SysConfigParams.CamImag.AutoSave && Math.Abs(marginWidth0 - _marginWidth2) > (10 * confMgr.SysConfigParams.Cm2px_x) && !string.IsNullOrEmpty(confMgr.SysConfigParams.CamImag.SavePath))
  1231. {
  1232. Records curRecord = Hashtable.Synchronized(htTask)[currKey] as Records;
  1233. string dirPath = Util.CreateSubDir(confMgr.SysConfigParams.CamImag.SavePath, new List<string> { $"{curRecord.BarCode}_{curRecord.BarCodeName}" });
  1234. AddImageSave($"{dirPath}Cam2-{Cam2Cnt}.bmp", img);
  1235. Log($"图像预处理", $"(相机2-图像{Cam2Cnt})-裁边异常:{marginWidth0}-{_marginWidth2} 》 {10 * confMgr.SysConfigParams.Cm2px_x}", WarningEnum.Normal, false);
  1236. }
  1237. _marginWidth2 = marginWidth0;
  1238. errStep = 5;
  1239. time += $"->相机2裁边({stopWatch.ElapsedMilliseconds})";
  1240. Log($"图像预处理", $"(相机2-图像{Cam2Cnt})-右图去重后:{mat.Width}*{mat.Height}," + $"重复值:{confMgr.SysConfigParams.MidCoin / 2} + 时间{time}", WarningEnum.Normal, false);
  1241. }
  1242. catch (Exception e)
  1243. {
  1244. Log($"图像处理", $"异常({errStep}):(相机2-图像{Cam2Cnt})-{e.Message}", WarningEnum.High);
  1245. }
  1246. //Log($"图像2入队列", $"相机2-{Cam1Cnt}", WarningEnum.Normal, false);
  1247. //Cv2.Flip(img, img, FlipMode.XY);//翻转
  1248. _matList2.Enqueue(new ScanPhotoInfo(1, Cam2Cnt++, mat.Clone(), picDis));
  1249. //System.GC.Collect();
  1250. }
  1251. else
  1252. Log($"相机2", $"(图像)-未扫码,图像丢弃!", WarningEnum.Low);
  1253. }
  1254. }
  1255. #endregion
  1256. //System.GC.Collect();
  1257. Thread.Sleep(50);
  1258. } while (!isBreakProcessRun());
  1259. //暂停中断
  1260. //stopWatch.Stop();
  1261. pStopWatch.Stop();
  1262. //_isRuning = false;
  1263. }
  1264. else
  1265. {
  1266. //防止内存爆满
  1267. AcquisitionMat acq = _LinecamDev2.GetFrames(10);
  1268. }
  1269. Thread.Sleep(50);
  1270. }
  1271. catch (Exception e)
  1272. {
  1273. _isRuning = false;
  1274. Log("运行报警", "相机1流程运行出错:" + e.Message + "\n", WarningEnum.High);
  1275. }
  1276. }
  1277. }
  1278. #endregion
  1279. #region 处理线程
  1280. int testCnt = 0;
  1281. /// <summary>
  1282. /// 后台运行主线程
  1283. /// </summary>
  1284. private void MainThreadFunction()
  1285. {
  1286. Mat acq1 = new Mat();
  1287. Mat acq2 = new Mat();
  1288. #if Online
  1289. #else
  1290. string imgfilePath1 = "D:\\CPL\\img\\L1.bmp";
  1291. string imgfilePath2 = "D:\\CPL\\img\\R1.bmp";
  1292. Mat timg1 = new Mat(imgfilePath1);
  1293. timg1 = timg1.Flip(FlipMode.XY);
  1294. Mat timg2 = new Mat(imgfilePath2);
  1295. timg2 = timg1.Flip(FlipMode.XY);
  1296. #endif
  1297. while (true)
  1298. {
  1299. int errStep = 0;
  1300. try
  1301. {
  1302. if (_cts.IsCancellationRequested)
  1303. break;
  1304. if (IsRuning)
  1305. {
  1306. ////暂停开始
  1307. //stopWatch.Start();
  1308. do
  1309. {
  1310. #if Online_One
  1311. #region 等待图片
  1312. #if Online
  1313. //采集图片
  1314. AcquisitionMat varacq1 = _LinecamDev1.GetFrames(10);
  1315. AcquisitionMat varacq2 = _LinecamDev2.GetFrames(10);
  1316. #else
  1317. AcquisitionMat varacq1 = new AcquisitionMat();
  1318. {
  1319. varacq1.GrabStatus = "GrabPass";
  1320. varacq1.Image = timg1;
  1321. Log($"图像预处理", $"模拟相机1-{Cam1Cnt}", WarningEnum.Normal, true);
  1322. }
  1323. AcquisitionMat varacq2 = new AcquisitionMat();
  1324. {
  1325. varacq2.GrabStatus = "GrabPass";
  1326. varacq2.Image = timg2;
  1327. Log($"图像预处理", $"模拟相机2-{Cam2Cnt}", WarningEnum.Normal, true);
  1328. }
  1329. #endif
  1330. if (varacq1.GrabStatus == "GrabPass")
  1331. {
  1332. acq1 = varacq1.Image.Clone();
  1333. _isHaveImgL = true;
  1334. Cam1Cnt++;
  1335. }
  1336. if (varacq2.GrabStatus == "GrabPass")
  1337. {
  1338. acq2 = varacq2.Image.Clone();
  1339. _isHaveImgR = true;
  1340. Cam2Cnt++;
  1341. }
  1342. if (_isHaveImgL && _isHaveImgR)
  1343. {
  1344. errStep = 1;
  1345. Stopwatch stopWatch = new Stopwatch();
  1346. string time = "";
  1347. Records curRecord = Hashtable.Synchronized(htTask)[currKey] as Records;
  1348. try
  1349. {
  1350. if (Cam1Cnt != Cam2Cnt)
  1351. {
  1352. Log($"图像预处理", $"图像错位{Cam1Cnt}-{Cam2Cnt}", WarningEnum.High);
  1353. continue;
  1354. }
  1355. #region 处理2次判定
  1356. if (!confMgr.SysConfigParams.OpenLengthCountStop)
  1357. {
  1358. //处理2次判定
  1359. //暂停:瑕疵二次判断
  1360. if (DefectPauseForUser)
  1361. {
  1362. stopWatch.Restart();
  1363. errStep = 2;
  1364. int liPhotoIndex = Cam1Cnt - confMgr.SysConfigParams.StopImageCnt - 1;
  1365. if (liPhotoIndex >= 0 && curRecord.dicPhoto_Defect.ContainsKey(liPhotoIndex) && curRecord.dicPhoto_Defect[liPhotoIndex] && curRecord.DefectInfoList != null)
  1366. {
  1367. if (defectPuaseList.Count > 0)
  1368. {
  1369. errStep = 3;
  1370. List<DefectInfo> lstEditDefect = defectPuaseList.Where(m => m.PhotoIndex == liPhotoIndex).ToList();
  1371. Log($"二次判断2", $"(图像{liPhotoIndex})已达观察台,瑕疵二次判断=》({string.Join(",", lstEditDefect.Select(m => m.Code).ToArray())})是否包含在({string.Join(",", curRecord.ProductInfo.DefectPauseOption.ToArray())})中。", WarningEnum.Normal, false);
  1372. //瑕疵选项过滤
  1373. if (curRecord.ProductInfo.DefectPauseOption.Count == 0 || lstEditDefect.Where(x => curRecord.ProductInfo.DefectPauseOption.Contains(x.Code)).Count() > 0)
  1374. {
  1375. Log($"二次判断2", $"(图像{liPhotoIndex})需瑕疵二次判断,已达观察台,进入暂停。速度:{GetSpd()}");
  1376. // if (lstEditDefect.Where(x => x.Code == "jietou").Count() > 0)
  1377. if (lstEditDefect.Where(x => DefectItemsPuaseNameList.Contains(x.Name)).Count() > 0)
  1378. {
  1379. Stop();
  1380. //获取完整数据
  1381. Thread.Sleep(500);
  1382. lstEditDefect = defectPuaseList.Where(m => m.PhotoIndex == liPhotoIndex).ToList();
  1383. //获取完整数据
  1384. #region 二级界面
  1385. #region 加载界面
  1386. if (defectPuaseImgList.ContainsKey(liPhotoIndex))
  1387. {
  1388. var pimage = (Bitmap)defectPuaseImgList[liPhotoIndex].ToBitmap().Clone();
  1389. var pmat = defectPuaseImgList[liPhotoIndex].Clone();
  1390. Task.Run(() =>
  1391. {
  1392. int liDefectCount = lstEditDefect.Count;
  1393. ImageShowFrm frmDefect = new ImageShowFrm(lstEditDefect, pimage);
  1394. //frmDefect.Show();
  1395. if (frmDefect.ShowDialog(_FatherFrm) == DialogResult.OK)
  1396. {
  1397. SysMgr.Instance.DelDefectEdit(curRecord, frmDefect.lstDel);
  1398. OnAutoRuning(new RunEventArgs(liPhotoIndex, lstEditDefect, curRecord, pmat, frmDefect.lstDel));
  1399. //double len = (double)this.lblLen.Tag;
  1400. //this.reDrawDefectPoints(curRecord.DefectInfoList, new double[] { 0, Math.Round(curRecord.FaceWidthMax + 0.005f, 2) }, new double[] { 0, len });
  1401. Log($"二次检测2", $"本次忽略{frmDefect.lstDel.Count}个瑕疵,本张图由{liDefectCount} -> {lstEditDefect.Count},总数{curRecord.DefectInfoList.Count}");
  1402. }
  1403. else
  1404. {
  1405. OnAutoRuning(new RunEventArgs(liPhotoIndex, lstEditDefect, curRecord, pmat, null));
  1406. }
  1407. });
  1408. }
  1409. else
  1410. Log($"二次检测2", $"本次图像已检测完成");
  1411. #endregion
  1412. //OnAutoRuning(new RunEventArgs(liPhotoIndex, lstEditDefect, curRecord, defectPuaseImgList[liPhotoIndex]));
  1413. #endregion
  1414. }
  1415. errStep = 3;
  1416. }
  1417. Log($"二次判断删除", $"{liPhotoIndex}-{testCnt}", WarningEnum.Normal, false);
  1418. lstEditDefect = defectPuaseList.Where(m => m.PhotoIndex == liPhotoIndex).ToList();
  1419. if (lstEditDefect.Count > 0 && defectPuaseImgList.Count > 0)
  1420. {
  1421. Mat mt;
  1422. defectPuaseImgList.TryRemove(lstEditDefect[0].PhotoIndex, out mt);
  1423. }
  1424. //foreach (var item in lstEditDefect)
  1425. {
  1426. lock (lock_defectPuase)
  1427. {
  1428. defectPuaseList.RemoveAll(m => m.PhotoIndex == liPhotoIndex);
  1429. //defectPuaseList.Remove(item);
  1430. }
  1431. }
  1432. }
  1433. else
  1434. Log($"二次判断2", $"(图像{liPhotoIndex})-缺陷未获得", WarningEnum.Low, false);
  1435. }
  1436. Log($"图像预处理", $"(图像{Cam1Cnt - 1})-处理2次判定:{stopWatch.ElapsedMilliseconds}", WarningEnum.Normal, false);
  1437. //else
  1438. // Log($"二次判断2", $"(图像{liPhotoIndex})-处理未跟上", WarningEnum.Low, false);
  1439. }
  1440. //time += $"->处理2次判定({stopWatch.ElapsedMilliseconds})";
  1441. }
  1442. #endregion
  1443. #region 相机图片保存
  1444. errStep = 4;
  1445. //保存图片
  1446. if (confMgr.SysConfigParams.CamImag.AutoSave && !string.IsNullOrEmpty(confMgr.SysConfigParams.CamImag.SavePath))
  1447. {
  1448. stopWatch.Restart();
  1449. string dirPath = Util.CreateSubDir(confMgr.SysConfigParams.CamImag.SavePath, new List<string> { $"{curRecord.BarCode}_{curRecord.BarCodeName}" });
  1450. AddImageSave($"{dirPath}Cam1-{Cam1Cnt}.bmp", acq1);
  1451. AddImageSave($"{dirPath}Cam2-{Cam2Cnt}.bmp", acq2);
  1452. Log($"图像预处理", $"(图像{Cam1Cnt - 1})-相机图片保存:{stopWatch.ElapsedMilliseconds}", WarningEnum.Normal, false);
  1453. }
  1454. if (_matList2.Count > listCntMax)
  1455. {
  1456. Log($"堆积过多", $"相机-缓存{_matList2.Count}大于{listCntMax}", WarningEnum.High);
  1457. //_matList2.Dequeue();
  1458. System.GC.Collect();
  1459. }
  1460. #endregion
  1461. //预处理
  1462. stopWatch.Restart();
  1463. #region 去重
  1464. if (confMgr.SysConfigParams.MidCoin > 0)//中间重合部分
  1465. {
  1466. errStep = 6;
  1467. int width = acq1.Width - confMgr.SysConfigParams.MidCoin / 2;
  1468. acq1 = OpencvUtils.CutImage(acq1, confMgr.SysConfigParams.MidCoin / 2, 0, width, acq1.Height);
  1469. acq2 = OpencvUtils.CutImage(acq2, 0, 0, width, acq2.Height);
  1470. time += $"->相机-去重({stopWatch.ElapsedMilliseconds})";
  1471. }
  1472. #endregion
  1473. #region 裁边
  1474. errStep = 7;
  1475. //左裁边
  1476. int marginWidth0;
  1477. acq1 = OpencvUtils.getMaxInsetRect2(acq1, false, confMgr.SysConfigParams.HolePx, out marginWidth0);
  1478. //右裁边
  1479. acq2 = OpencvUtils.getMaxInsetRect2(acq2, true, confMgr.SysConfigParams.HolePx, out marginWidth0);
  1480. time += $"->相机裁边({stopWatch.ElapsedMilliseconds})";
  1481. #endregion
  1482. #region 拼接
  1483. errStep = 8;
  1484. //水平合并l
  1485. Mat mat;
  1486. mat = OpencvUtils.MergeImage_sameSize(new Mat[] { acq2, acq1 });
  1487. time += $"->图1+2合并({stopWatch.ElapsedMilliseconds})";
  1488. #endregion
  1489. #region 镜像
  1490. errStep = 5;
  1491. //图像镜像
  1492. mat = mat.Flip(FlipMode.XY);
  1493. time += $"->相机翻转({stopWatch.ElapsedMilliseconds})";
  1494. #endregion
  1495. #region 填充
  1496. errStep = 9;
  1497. //比例缩放图片
  1498. int xw;
  1499. int resizeWidth = OpencvUtils.GetWidthForResize(acq1.Width + acq2.Width - confMgr.SysConfigParams.MidCoin);
  1500. if (resizeWidth == 0)
  1501. throw new Exception("GetWidthForResize result 0 失败!");
  1502. var resize = new System.Drawing.Size(resizeWidth, OpencvUtils.image_height * 2);//固定8192*2张*4096
  1503. mat = OpencvUtils.Resize(mat, resize.Width, resize.Height, out xw);
  1504. time += $"->填充({stopWatch.ElapsedMilliseconds})";
  1505. #endregion
  1506. #region 处理
  1507. errStep = 10;
  1508. defectLib.add(new DefectTask()
  1509. {
  1510. modelName = curRecord.ProductInfo.ModelName,
  1511. record = curRecord,
  1512. bmp = mat,
  1513. bmpTag = mat.Clone(),
  1514. photoIndex = Cam1Cnt - 1,//0-n 首张必需为0,因下面计算长度是从0开始
  1515. widthRatio = 1.0f,//等比例缩放,高度不变
  1516. qualifiedLimitList = curRecord.ProductInfo.QualifiedLimitList,
  1517. labelDic = GetDefectCode(),
  1518. finishEvent = callBackDefectEvent,
  1519. xw = xw,
  1520. cm2px_x = confMgr.SysConfigParams.Cm2px_x,
  1521. cm2px_y = confMgr.SysConfigParams.Cm2px_y,
  1522. expand_pixel = confMgr.SysConfigParams.Expand_pixel,
  1523. });
  1524. curRecord.ScannerPhotoCount++;
  1525. errStep = 11;
  1526. time += $"->加入瑕疵待检队列({stopWatch.ElapsedMilliseconds})";
  1527. #endregion
  1528. #region 门幅
  1529. float faceWidthX_cm = (float)Math.Round((Cam1Cnt) * mat.Height * 1.0f / confMgr.SysConfigParams.Cm2px_y, 2);
  1530. float faceWidthY_cm = (float)Math.Round((mat.Width + confMgr.SysConfigParams.HolePx * 2) * 1.0f / confMgr.SysConfigParams.Cm2px_x, 2);
  1531. if (curRecord.FaceWidthMin == 0 || curRecord.FaceWidthMin > faceWidthY_cm)
  1532. curRecord.FaceWidthMin = faceWidthY_cm;
  1533. if (curRecord.FaceWidthMax < faceWidthY_cm)
  1534. curRecord.FaceWidthMax = faceWidthY_cm;
  1535. var point = new float[] { faceWidthX_cm, faceWidthY_cm };
  1536. curRecord.FacePointList.Add(point);
  1537. errStep = 12;
  1538. //判定门幅
  1539. //if (x < XSizeRange[0])
  1540. // Log($"绘图", $"门幅宽度超限 1!!!! {x}<{XSizeRange[0]}", WarningEnum.High);
  1541. //if (x > XSizeRange[1])
  1542. // Log($"绘图", $"门幅宽度超限 2!!!! {x}>{XSizeRange[1]}", WarningEnum.High);
  1543. //if (item[1] < YSizeRange[0])
  1544. // Log($"绘图", $"门幅宽度超限 3!!!! {item[1]}<{YSizeRange[0]}", WarningEnum.High);
  1545. //if (item[1] > YSizeRange[1])
  1546. // Log($"绘图", $"门幅宽度超限 4!!!! {item[1]}>{YSizeRange[1]}", WarningEnum.High);
  1547. //显示门幅绘图
  1548. OnAutoRuning(new RunEventArgs(curRecord.FacePointList));
  1549. errStep = 13;
  1550. time += $"->门幅刷新({stopWatch.ElapsedMilliseconds})";
  1551. #endregion
  1552. #region 长度剩余提醒
  1553. errStep = 14;
  1554. //长度剩余提醒
  1555. if (CurrProductModel.residueWarnningLen > 0 && curRecord.ErpLen > 0 && CurrProductModel.residueWarnningLen >= curRecord.ErpLen - curRecord.Len)
  1556. {
  1557. Log($"长度告警", $"已达剩余长度不足提醒!({curRecord.ErpLen - curRecord.Len}<={CurrProductModel.residueWarnningLen})", WarningEnum.Low);
  1558. }
  1559. #endregion
  1560. }
  1561. catch (Exception ex)
  1562. {
  1563. curRecord.ScannerPhotoFinishCount++;//失败时不能因数量不一致无法保存
  1564. Log($"图像预处理", $"异常({errStep}):(图像{Cam1Cnt-1})-{ex.Message}", WarningEnum.High);
  1565. //string dirPath = FileUtil.initFolder($"{Config.ImagePath}{curRecord.BatchId}_{curRecord.ReelId}\\Err\\");
  1566. //OpenCvSharp.Extensions.BitmapConverter.ToBitmap(scanPhotos0.mat).Save($"{dirPath}{scanPhotos0.photoIndex}_0_Step{errStep}.bmp", ImageFormat.Bmp);
  1567. //OpenCvSharp.Extensions.BitmapConverter.ToBitmap(scanPhotos1.mat).Save($"{dirPath}{scanPhotos1.photoIndex}_1_Step{errStep}.bmp", ImageFormat.Bmp);
  1568. }
  1569. finally
  1570. {
  1571. Log($"图像预处理", $"(图像{Cam1Cnt - 1})-进度计时:{time}", WarningEnum.Normal, false);
  1572. //task = null;
  1573. //System.GC.Collect();
  1574. }
  1575. }
  1576. else
  1577. continue;
  1578. #endregion
  1579. #else
  1580. #region 长度剩余提醒
  1581. //长度剩余提醒
  1582. Records curRecord = Hashtable.Synchronized(htTask)[currKey] as Records;
  1583. if (CurrProductModel.residueWarnningLen > 0 && curRecord.ErpLen > 0 && CurrProductModel.residueWarnningLen >= curRecord.ErpLen - curRecord.Len)
  1584. {
  1585. Log($"长度告警", $"已达剩余长度不足提醒!({curRecord.ErpLen - curRecord.Len}<={CurrProductModel.residueWarnningLen})", WarningEnum.Low);
  1586. }
  1587. #endregion
  1588. #region 图像裁边预处理
  1589. //预处理,队列都有数据,且数据长度一致
  1590. #if Online_defect
  1591. ScanPhotoInfo peek1;
  1592. ScanPhotoInfo peek2;
  1593. if (_matList1.Count > 0 && _matList2.Count > 0 )
  1594. {
  1595. _matList1.TryPeek(out peek1);
  1596. _matList2.TryPeek(out peek2);
  1597. if (peek1 != null && peek2 !=null && peek1.photoIndex != peek2.photoIndex)
  1598. continue;
  1599. Stopwatch stopWatch = new Stopwatch();
  1600. ScanPhotoInfo scanPhotos0;
  1601. if(!_matList1.TryDequeue(out scanPhotos0))
  1602. Log($"图像出队列", $"异常相机1队列出队失败", WarningEnum.High);
  1603. ScanPhotoInfo scanPhotos1;
  1604. if(!_matList2.TryDequeue(out scanPhotos1))
  1605. Log($"图像出队列", $"异常相机2队列出队失败", WarningEnum.High);
  1606. //Log($"图像出队列", $"相机1-{scanPhotos0.photoIndex}", WarningEnum.Normal, false);
  1607. curRecord.dicPhoto_Defect.TryAdd(scanPhotos0.photoIndex, false);//加入索引,默认无瑕疵
  1608. //Log($"图像拼接处理", $"相机1-{scanPhotos0.photoIndex},相机2-{scanPhotos1.photoIndex}", WarningEnum.Normal, false);
  1609. string time = $"图像位置:{scanPhotos1.CurrDis}";
  1610. stopWatch.Start();
  1611. try
  1612. {
  1613. Mat mat;
  1614. Mat mat0;
  1615. Mat mat1;
  1616. //lock (_lockOpenCV)
  1617. {
  1618. if (scanPhotos0.mat.Height != scanPhotos1.mat.Height)
  1619. {
  1620. Log($"警告", $"两相机采集图高度不一致({scanPhotos0.photoIndex}),dev1.Height={scanPhotos0.mat.Height},dev2.Height={scanPhotos1.mat.Height},重新resize...", WarningEnum.Low);
  1621. if (scanPhotos0.mat.Height > scanPhotos1.mat.Height)
  1622. scanPhotos1.mat = OpencvUtils.ResizeMat(scanPhotos1.mat, scanPhotos0.mat.Width, scanPhotos0.mat.Height);
  1623. else
  1624. scanPhotos0.mat = OpencvUtils.ResizeMat(scanPhotos0.mat, scanPhotos1.mat.Width, scanPhotos1.mat.Height);
  1625. }
  1626. errStep = 1;
  1627. //反转+相机索引调换
  1628. mat1 = scanPhotos1.mat;
  1629. mat0 = scanPhotos0.mat;
  1630. //水平合并l
  1631. mat = OpencvUtils.MergeImage_sameSize(new Mat[] { mat0, mat1 });//这里相机反装,左右反转下
  1632. //Log($"合并", $"(图像{scanPhotos0.photoIndex})-裁边去孔洞后:({mat0.Width}+{mat1.Width});合并后(去孔洞):{mat.Width}*{mat.Height}", WarningEnum.Normal, false);
  1633. //float widthRatio = mat.Width * 1.0f / resize.Width;//宽度比例
  1634. time += $"->图1+2合并({stopWatch.ElapsedMilliseconds})";
  1635. }
  1636. errStep = 2;
  1637. //门幅更新(含两侧孔洞)x,y cm
  1638. float faceWidthX_cm = (float)Math.Round((scanPhotos0.photoIndex + 1) * mat.Height * 1.0f / confMgr.SysConfigParams.Cm2px_y, 2);
  1639. float faceWidthY_cm = (float)Math.Round((mat.Width + confMgr.SysConfigParams.HolePx * 2) * 1.0f / confMgr.SysConfigParams.Cm2px_x, 2);
  1640. #else
  1641. string imgfilePath = "C:\\Users\\fang\\Desktop\\新建文件夹\\boyi lou";
  1642. if (!Directory.Exists(imgfilePath))
  1643. {
  1644. Log($"图像处理", $"模拟错误-路径错误{imgfilePath}", WarningEnum.High);
  1645. break;
  1646. }
  1647. string[] files = Directory.GetFiles(imgfilePath, $"*.bmp", SearchOption.TopDirectoryOnly);
  1648. if (files.Length > 0 && Cam1Cnt < files.Length)
  1649. {
  1650. Stopwatch stopWatch = new Stopwatch();
  1651. string time = "";
  1652. //stopWatch.Start();
  1653. ScanPhotoInfo scanPhotos0 = new ScanPhotoInfo(0, Cam1Cnt, new Mat(4096, 4096 * 2, MatType.CV_8UC3, new Scalar(0, 0, 0)));
  1654. ScanPhotoInfo scanPhotos1 = new ScanPhotoInfo(1, Cam1Cnt, new Mat(4096, 4096 * 2, MatType.CV_8UC3, new Scalar(0, 0, 0)));
  1655. stopWatch.Start();
  1656. errStep = 0;
  1657. try
  1658. {
  1659. Log($"图像处理", $"模拟{files[Cam1Cnt]}");
  1660. Mat mat = new Mat(files[Cam1Cnt]);
  1661. Cam1Cnt++;
  1662. Mat mat0 = scanPhotos1.mat;
  1663. Mat mat1 = scanPhotos0.mat;
  1664. float faceWidthX_cm = (float)Math.Round((scanPhotos0.photoIndex + 1) * mat.Height * 1.0f / confMgr.SysConfigParams.Cm2px_y, 2);
  1665. float faceWidthY_cm = (float)Math.Round((mat.Width + confMgr.SysConfigParams.HolePx * 2) * 1.0f / confMgr.SysConfigParams.Cm2px_x, 2);
  1666. #endif
  1667. //显示图片
  1668. //OnAutoRuning(new RunEventArgs(mat.Clone()));
  1669. //faceWidthX_cm = (float)Math.Round(faceWidthX_cm, 2);
  1670. //faceWidthY_cm = (float)Math.Round(faceWidthY_cm, 2);
  1671. if (curRecord.FaceWidthMin == 0 || curRecord.FaceWidthMin > faceWidthY_cm)
  1672. curRecord.FaceWidthMin = faceWidthY_cm;
  1673. if (curRecord.FaceWidthMax < faceWidthY_cm)
  1674. curRecord.FaceWidthMax = faceWidthY_cm;
  1675. var point = new float[] { faceWidthX_cm, faceWidthY_cm };// new System.Drawing.PointF(faceWidthX_cm, faceWidthY_cm);
  1676. //Log($"门幅", $"(图像{scanPhotos0.photoIndex})-({scanPhotos0.photoIndex})位置:{point[0]}; 幅宽:{point[1]}", WarningEnum.Normal, false);
  1677. curRecord.FacePointList.Add(point);
  1678. errStep = 3;
  1679. //判定门幅
  1680. //if (x < XSizeRange[0])
  1681. // Log($"绘图", $"门幅宽度超限 1!!!! {x}<{XSizeRange[0]}", WarningEnum.High);
  1682. //if (x > XSizeRange[1])
  1683. // Log($"绘图", $"门幅宽度超限 2!!!! {x}>{XSizeRange[1]}", WarningEnum.High);
  1684. //if (item[1] < YSizeRange[0])
  1685. // Log($"绘图", $"门幅宽度超限 3!!!! {item[1]}<{YSizeRange[0]}", WarningEnum.High);
  1686. //if (item[1] > YSizeRange[1])
  1687. // Log($"绘图", $"门幅宽度超限 4!!!! {item[1]}>{YSizeRange[1]}", WarningEnum.High);
  1688. //显示门幅绘图
  1689. OnAutoRuning(new RunEventArgs(curRecord.FacePointList));
  1690. errStep = 7;
  1691. time += $"->门幅刷新({stopWatch.ElapsedMilliseconds})";
  1692. //去除两侧孔洞(门幅计算时不能去除)
  1693. //if (Config.MarginHoleWidth > 0)
  1694. // mat = OpenCVUtil.cutImage(mat, Config.MarginHoleWidth, 0, mat.Width - Config.MarginHoleWidth * 2, mat.Height);
  1695. #region 速度
  1696. //计算速度
  1697. if (!confMgr.SysConfigParams.OpenLengthCount)
  1698. {
  1699. double lenMi = Math.Round(faceWidthX_cm / 100, 2);
  1700. curRecord.Len = lenMi;
  1701. curRecord.TimeLen = pStopWatch.ElapsedMilliseconds / 1000.0d / 60.0d;//总时间 分
  1702. double aveSpd = Math.Round(lenMi / curRecord.TimeLen, 2);
  1703. //显示平均速度
  1704. OnAutoRuning(new RunEventArgs(lenMi, aveSpd));
  1705. errStep = 9;
  1706. time += $"->速度刷新({stopWatch.ElapsedMilliseconds})";
  1707. }
  1708. #endregion
  1709. #if false
  1710. #region 处理2次判定
  1711. if (!confMgr.SysConfigParams.OpenLengthCountStop)
  1712. {
  1713. //处理2次判定
  1714. //暂停:瑕疵二次判断
  1715. if (DefectPauseForUser && defectPuaseList.Count > 0)
  1716. {
  1717. errStep = 11;
  1718. int liPhotoIndex = scanPhotos0.photoIndex - confMgr.SysConfigParams.StopImageCnt;
  1719. //Log($"二次判断2", $"图像{scanPhotos0.photoIndex} {liPhotoIndex}={scanPhotos0.photoIndex}-{confMgr.SysConfigParams.StopImageCnt};{JsonConvert.SerializeObject(curRecord.dicPhoto_Defect)}", WarningEnum.Normal, false);
  1720. if (liPhotoIndex >= 0 && curRecord.dicPhoto_Defect[liPhotoIndex] && curRecord.DefectInfoList != null)
  1721. {
  1722. errStep = 12;
  1723. List<DefectInfo> lstEditDefect = defectPuaseList.Where(m => m.PhotoIndex == liPhotoIndex).ToList();
  1724. Log($"二次判断2", $"(图像{liPhotoIndex})已达观察台,瑕疵二次判断=》({string.Join(",", lstEditDefect.Select(m => m.Code).ToArray())})是否包含在({string.Join(",", curRecord.ProductInfo.DefectPauseOption.ToArray())})中。", WarningEnum.Normal, false);
  1725. //瑕疵选项过滤
  1726. if (curRecord.ProductInfo.DefectPauseOption.Count == 0 || lstEditDefect.Where(x => curRecord.ProductInfo.DefectPauseOption.Contains(x.Code)).Count() > 0)
  1727. {
  1728. Log($"二次判断2", $"(图像{liPhotoIndex})需瑕疵二次判断,已达观察台,进入暂停。");
  1729. // if (lstEditDefect.Where(x => x.Code == "jietou").Count() > 0)
  1730. if (lstEditDefect.Where(x => DefectItemsPuaseNameList.Contains(x.Name)).Count() > 0)
  1731. {
  1732. Stop();
  1733. //获取完整数据
  1734. Thread.Sleep(500);
  1735. lstEditDefect = defectPuaseList.Where(m => m.PhotoIndex == liPhotoIndex).ToList();
  1736. //获取完整数据
  1737. #region 二级界面
  1738. #region 加载界面
  1739. if (defectPuaseImgList.ContainsKey(liPhotoIndex))
  1740. {
  1741. var pimage = (Bitmap)defectPuaseImgList[liPhotoIndex].ToBitmap().Clone();
  1742. Task.Run(() =>
  1743. {
  1744. int liDefectCount = lstEditDefect.Count;
  1745. ImageShowFrm frmDefect = new ImageShowFrm(lstEditDefect, pimage);
  1746. //frmDefect.Show();
  1747. if (frmDefect.ShowDialog() == DialogResult.OK)
  1748. {
  1749. SysMgr.Instance.DelDefectEdit(curRecord, frmDefect.lstDel);
  1750. OnAutoRuning(new RunEventArgs(liPhotoIndex, lstEditDefect, curRecord, defectPuaseImgList[liPhotoIndex], frmDefect.lstDel));
  1751. //double len = (double)this.lblLen.Tag;
  1752. //this.reDrawDefectPoints(curRecord.DefectInfoList, new double[] { 0, Math.Round(curRecord.FaceWidthMax + 0.005f, 2) }, new double[] { 0, len });
  1753. Log($"二次检测2", $"本次忽略{frmDefect.lstDel.Count}个瑕疵,本张图由{liDefectCount} -> {lstEditDefect.Count},总数{curRecord.DefectInfoList.Count}");
  1754. }
  1755. else
  1756. {
  1757. OnAutoRuning(new RunEventArgs(liPhotoIndex, lstEditDefect, curRecord, defectPuaseImgList[liPhotoIndex], null));
  1758. }
  1759. });
  1760. }
  1761. else
  1762. Log($"二次检测2", $"本次图像已检测完成");
  1763. #endregion
  1764. //OnAutoRuning(new RunEventArgs(liPhotoIndex, lstEditDefect, curRecord, defectPuaseImgList[liPhotoIndex]));
  1765. #endregion
  1766. }
  1767. errStep = 18;
  1768. }
  1769. Log($"二次判断删除", $"{liPhotoIndex}-{testCnt}", WarningEnum.Normal, false);
  1770. lock (lock_defectPuase)
  1771. {
  1772. lstEditDefect = defectPuaseList.Where(m => m.PhotoIndex == liPhotoIndex).ToList();
  1773. if (lstEditDefect.Count > 0 && defectPuaseImgList.Count > 0)
  1774. defectPuaseImgList.Remove(lstEditDefect[0].PhotoIndex);
  1775. foreach (var item in lstEditDefect)
  1776. {
  1777. defectPuaseList.Remove(item);
  1778. }
  1779. }
  1780. }
  1781. }
  1782. time += $"->处理2次判定({stopWatch.ElapsedMilliseconds})";
  1783. }
  1784. #endregion
  1785. #endif
  1786. //----缺陷队列
  1787. //比例缩放图片
  1788. int xw;
  1789. int resizeWidth = OpencvUtils.GetWidthForResize(mat0.Width + mat1.Width - confMgr.SysConfigParams.MidCoin);
  1790. if (resizeWidth == 0)
  1791. throw new Exception("GetWidthForResize result 0 失败!");
  1792. var resize = new System.Drawing.Size(resizeWidth, OpencvUtils.image_height * 2);//固定8192*2张*4096
  1793. mat = OpencvUtils.Resize(mat, resize.Width, resize.Height, out xw);
  1794. //Log($"图像处理", $"(图像{scanPhotos0.photoIndex})-合成图resize后:{mat.Width}*{mat.Height}", WarningEnum.Normal, false);
  1795. defectLib.add(new DefectTask()
  1796. {
  1797. modelName = curRecord.ProductInfo.ModelName,
  1798. record = curRecord,
  1799. bmp = mat,
  1800. bmpTag = mat.Clone(),
  1801. photoIndex = scanPhotos0.photoIndex,//0-n 首张必需为0,因下面计算长度是从0开始
  1802. widthRatio = 1.0f,//等比例缩放,高度不变
  1803. qualifiedLimitList = curRecord.ProductInfo.QualifiedLimitList,
  1804. labelDic = GetDefectCode(),
  1805. finishEvent = callBackDefectEvent,
  1806. xw = xw,
  1807. cm2px_x = confMgr.SysConfigParams.Cm2px_x,
  1808. cm2px_y = confMgr.SysConfigParams.Cm2px_y,
  1809. expand_pixel = confMgr.SysConfigParams.Expand_pixel,
  1810. CurrDis = scanPhotos1.CurrDis,
  1811. });
  1812. curRecord.ScannerPhotoCount++;
  1813. errStep = 10;
  1814. time += $"->加入瑕疵待检队列({stopWatch.ElapsedMilliseconds})";
  1815. }
  1816. catch (Exception ex)
  1817. {
  1818. curRecord.ScannerPhotoFinishCount++;//失败时不能因数量不一致无法保存
  1819. Log( $"图像处理", $"异常({errStep}):(图像{scanPhotos0.photoIndex})-{ex.Message}", WarningEnum.High);
  1820. //string dirPath = FileUtil.initFolder($"{Config.ImagePath}{curRecord.BatchId}_{curRecord.ReelId}\\Err\\");
  1821. //OpenCvSharp.Extensions.BitmapConverter.ToBitmap(scanPhotos0.mat).Save($"{dirPath}{scanPhotos0.photoIndex}_0_Step{errStep}.bmp", ImageFormat.Bmp);
  1822. //OpenCvSharp.Extensions.BitmapConverter.ToBitmap(scanPhotos1.mat).Save($"{dirPath}{scanPhotos1.photoIndex}_1_Step{errStep}.bmp", ImageFormat.Bmp);
  1823. }
  1824. finally
  1825. {
  1826. Log($"图像处理", $"(图像{scanPhotos0.photoIndex})-进度计时:{time}", WarningEnum.Normal, false);
  1827. scanPhotos0.mat.Dispose();
  1828. scanPhotos1.mat.Dispose();
  1829. scanPhotos0 = scanPhotos1 = null;
  1830. //task = null;
  1831. //System.GC.Collect();
  1832. }
  1833. }
  1834. #endregion
  1835. #endif
  1836. Thread.Sleep(20);
  1837. } while (!isBreakProcessRun());
  1838. //暂停中断
  1839. //stopWatch.Stop();
  1840. pStopWatch.Stop();
  1841. _isRuning = false;
  1842. }
  1843. #if Online_One
  1844. else
  1845. {
  1846. //防止内存爆满
  1847. AcquisitionMat tacq1 = _LinecamDev1.GetFrames(10);
  1848. AcquisitionMat tacq2 = _LinecamDev2.GetFrames(10);
  1849. }
  1850. #endif
  1851. Thread.Sleep(20);
  1852. }
  1853. catch (Exception e)
  1854. {
  1855. _isRuning = false;
  1856. Log("运行报警", $"流程运行出错{errStep}:" + e.Message + "\n", WarningEnum.High);
  1857. }
  1858. }
  1859. }
  1860. #endregion
  1861. #endregion
  1862. #region 模型label
  1863. private JArray _defectItemList;
  1864. /// <summary>
  1865. /// 获取模型对应标签信息
  1866. /// </summary>
  1867. private void GetDefectAllLabel()
  1868. {
  1869. string labels = CurrProductModel.ModelName.Replace(".trt", ".json");
  1870. string configPath = confMgr.SysConfigParams.AIModelPath + $"\\{labels}";
  1871. string lsTmp = File.ReadAllText(configPath);
  1872. JArray defectItemList = JArray.Parse(lsTmp);
  1873. _defectItemList = defectItemList;
  1874. //var item = defectItemList.FirstOrDefault(m => m.Value<int>("id") == id);
  1875. //if (item == null)
  1876. // return null;
  1877. //return (JObject)item;
  1878. }
  1879. public JArray GetDefectItemList()
  1880. { return _defectItemList; }
  1881. /// <summary>
  1882. /// 根据id获取标签信息
  1883. /// </summary>
  1884. /// <param name="id"></param>
  1885. /// <returns></returns>
  1886. public JObject GetDefectLabel(int id)
  1887. {
  1888. if (_defectItemList != null && _defectItemList.Count > 0)
  1889. {
  1890. var item = _defectItemList.FirstOrDefault(m => m.Value<int>("id") == id);
  1891. if (item == null)
  1892. return null;
  1893. return (JObject)item;
  1894. }
  1895. else
  1896. return null;
  1897. }
  1898. /// <summary>
  1899. /// 根据name获取标签信息
  1900. /// </summary>
  1901. /// <param name="id"></param>
  1902. /// <returns></returns>
  1903. public JObject GetDefectLabel(string name)
  1904. {
  1905. if (_defectItemList != null && _defectItemList.Count > 0)
  1906. {
  1907. var item = _defectItemList.FirstOrDefault(m => m.Value<string>("name") == name);
  1908. if (item == null)
  1909. return null;
  1910. return (JObject)item;
  1911. }
  1912. else
  1913. return null;
  1914. }
  1915. public JObject GetDefectLabel(string modelName, string name)
  1916. {
  1917. string labels = modelName.Replace(".trt", ".json");
  1918. string configPath = confMgr.SysConfigParams.AIModelPath + $"\\{labels}";
  1919. string lsTmp = File.ReadAllText(configPath);
  1920. JArray defectItemList = JArray.Parse(lsTmp);
  1921. if (defectItemList != null && defectItemList.Count > 0)
  1922. {
  1923. var item = defectItemList.FirstOrDefault(m => m.Value<string>("name") == name);
  1924. if (item == null)
  1925. return null;
  1926. return (JObject)item;
  1927. }
  1928. else
  1929. return null;
  1930. }
  1931. public string GetDefectName(string code)
  1932. {
  1933. if (_defectItemList != null && _defectItemList.Count > 0)
  1934. {
  1935. var item = _defectItemList.FirstOrDefault(m => m.Value<string>("code") == code);
  1936. if (item == null)
  1937. return null;
  1938. return item.Value<string>("name");
  1939. }
  1940. else
  1941. return null;
  1942. }
  1943. public string GetDefectName(string modelName, string code)
  1944. {
  1945. string labels = modelName.Replace(".trt", ".json");
  1946. string configPath = confMgr.SysConfigParams.AIModelPath + $"\\{labels}";
  1947. string lsTmp = File.ReadAllText(configPath);
  1948. JArray defectItemList = JArray.Parse(lsTmp);
  1949. if (defectItemList != null && defectItemList.Count > 0)
  1950. {
  1951. var item = defectItemList.FirstOrDefault(m => m.Value<string>("code") == code);
  1952. if (item == null)
  1953. return null;
  1954. return item.Value<string>("name");
  1955. }
  1956. else
  1957. return null;
  1958. }
  1959. public Dictionary<int, string> GetDefectCode()
  1960. {
  1961. Dictionary<int, string> dic = new Dictionary<int, string>();
  1962. for (int i = 0; i < _defectItemList.Count; i++)
  1963. {
  1964. var tt = _defectItemList[i];
  1965. dic.Add(tt.Value<int>("id"), tt.Value<string>("code"));
  1966. }
  1967. return dic;
  1968. }
  1969. #endregion
  1970. #region 推理完成处理
  1971. private void callBackDefectEvent(DefectTask res)
  1972. {
  1973. {
  1974. int step = 0;
  1975. try
  1976. {
  1977. Stopwatch stopWatch = new Stopwatch();
  1978. stopWatch.Start();
  1979. string time = "";
  1980. //Log($"检测完成", $"图像队列:{res.record.ScannerPhotoFinishCount + 1}/{res.record.ScannerPhotoCount} (图像{res.photoIndex})检测结果:{res.isSucceed}", WarningEnum.Normal, false);
  1981. //string dirPath = FileUtil.initFolder($"{Config.ImagePath}{res.record.BatchId}_{res.record.ReelId}\\");
  1982. //string dirSourcePath = FileUtil.initFolder($"{Config.ImagePath}{res.record.BatchId}_{res.record.ReelId}\\源图\\");
  1983. //Cv2.Flip(res.bmp, res.bmp, FlipMode.XY);//翻转
  1984. //显示打标图片
  1985. if (res.excelTable.Rows.Count > 0)
  1986. OnAutoRuning(new RunEventArgs(res.bmpTag));
  1987. else
  1988. OnAutoRuning(new RunEventArgs(res.bmp));
  1989. string dirPath = Util.CreateSubDir(confMgr.SysConfigParams.DefectSrcImag.SavePath, new List<string> { $"{ res.record.BarCode}_{ res.record.BarCodeName}" });
  1990. if (confMgr.SysConfigParams.DefectSrcImag.AutoSave)//保存所有原图
  1991. {
  1992. AddImageSave($"{dirPath}{res.photoIndex}.bmp", res.bmp);
  1993. //OpenCvSharp.Extensions.BitmapConverter.ToBitmap(res.bmp).Save($"{dirPath}{res.photoIndex}.bmp", ImageFormat.Bmp);
  1994. }
  1995. if (res.isSucceed)
  1996. {
  1997. step = 1;
  1998. Log($"检测完成", $"(图像{res.photoIndex})-瑕疵检测完成,共{res.excelTable.Rows.Count}个瑕疵!各环节用时:{string.Join(",", res.stopwatch)}", WarningEnum.Normal, false);
  1999. //AddTextEvent(DateTime.Now,$"打标完成", $"第 ({res.photoIndex}) 张照片,计算过程:{res.resultInfo}");
  2000. //if (!Config.IsSaveAllImage && Config.IsSaveDefectSourceImage)
  2001. // OpenCvSharp.Extensions.BitmapConverter.ToBitmap(res.bmp).Save($"{dirSourcePath}{res.photoIndex}.bmp", ImageFormat.Bmp);
  2002. time += $"(图像{res.photoIndex})";
  2003. step = 2;
  2004. if (res.excelTable.Rows.Count > 0)
  2005. {
  2006. res.record.dicPhoto_Defect[res.photoIndex] = true;//改为此图有瑕疵
  2007. step = 3;
  2008. res.record.DefectTotalCount += res.excelTable.Rows.Count;
  2009. if (res.record.DefectInfoList == null)
  2010. res.record.DefectInfoList = new List<DefectInfo>();
  2011. step = 4;
  2012. JObject defectNameInfo;
  2013. DefectInfo defectInfo = null;
  2014. List<object[]> dataRowlist = new List<object[]>();
  2015. long preTicks = pStopWatch.ElapsedMilliseconds;// DateTime.Now.Ticks;
  2016. for (int i = 0; i < res.lstDefectBmp.Count; i++)
  2017. {
  2018. step = 5 + i * 10;
  2019. defectNameInfo = GetDefectLabel(int.Parse(res.excelTable.Rows[i]["类别"].ToString()));
  2020. if(defectNameInfo == null)
  2021. {
  2022. Log($"告警", $"模型标签为空,或未找到标签!", WarningEnum.High);
  2023. continue;
  2024. }
  2025. defectInfo = new DefectInfo
  2026. {
  2027. PhotoIndex = res.photoIndex,
  2028. Code = defectNameInfo.Value<string>("code"),
  2029. Name = defectNameInfo.Value<string>("name"),
  2030. X = double.Parse(res.excelTable.Rows[i]["X"].ToString()),//cm
  2031. Y = Math.Round((res.photoIndex * res.bmp.Height * 1.0d / confMgr.SysConfigParams.Cm2px_y + double.Parse(res.excelTable.Rows[i]["Y"].ToString())), 2),//cm
  2032. Width = double.Parse(res.excelTable.Rows[i]["W"].ToString()),//cm
  2033. Height = double.Parse(res.excelTable.Rows[i]["H"].ToString()),//cm
  2034. ZXD = double.Parse(res.excelTable.Rows[i]["置信度"].ToString()),
  2035. Contrast = double.Parse(res.excelTable.Rows[i]["对比度"].ToString()),
  2036. Target = int.Parse(res.excelTable.Rows[i]["目标"].ToString()),
  2037. image = res.lstDefectBmp[i].Clone(),
  2038. PicY = double.Parse(res.excelTable.Rows[i]["Y"].ToString()),//cm
  2039. CurrDis = res.CurrDis,
  2040. };
  2041. defectInfo.ModifyUserCode = defectInfo.CreateUserCode = res.record.CreateUserCode;
  2042. step = 6 + i * 10;
  2043. //判定是否加入二次判断
  2044. if (DefectItemsPuaseNameList.Contains(defectInfo.Name))
  2045. {
  2046. lock (lock_defectPuase)
  2047. {
  2048. defectPuaseList.Add(defectInfo);
  2049. }
  2050. if (!defectPuaseImgList.ContainsKey(res.photoIndex))
  2051. defectPuaseImgList.TryAdd(res.photoIndex, res.bmpTag.Clone());
  2052. }
  2053. //判定是否加入打标
  2054. if (DefectItemsDBNameList.Contains(defectInfo.Name))
  2055. {
  2056. lock (lock_defectDB)
  2057. {
  2058. defectDBList.Add(defectInfo);
  2059. }
  2060. }
  2061. res.record.DefectInfoList.Add(defectInfo);
  2062. defectInfo.uid = preTicks++;// res.record.DefectInfoList.Count;//程序中的唯一索引,用于移除用索引
  2063. //AddTextEvent(DateTime.Now,$"打标完成", $"第{i}个缺陷:{ JsonConvert.SerializeObject(defectInfo)}; Y={res.photoIndex * res.bmp.Height * 1.0d / Config.cm2px_y}+{res.excelTable.Rows[i]["Y"].ToString()}");
  2064. step = 7 + i * 10;
  2065. //保存打标小图
  2066. if (confMgr.SysConfigParams.DefectSmallImag.AutoSave)
  2067. {
  2068. dirPath = Util.CreateSubDir(confMgr.SysConfigParams.DefectSmallImag.SavePath, new List<string> { $"{res.record.BarCode}_{res.record.BarCodeName}" });
  2069. string filename = $"{dirPath}{res.photoIndex}_X{defectInfo.X}_Y{defectInfo.Y}_W{defectInfo.Width}_H{defectInfo.Height}_目标{defectInfo.Target}_类别{defectInfo.Code}_置信度{defectInfo.ZXD}.jpg";
  2070. //OpenCvSharp.Extensions.BitmapConverter.ToBitmap(res.lstDefectBmp[i]).Save(filename, ImageFormat.Jpeg);
  2071. AddImageSave(filename, res.lstDefectBmp[i]);
  2072. defectInfo.TagFilePath = filename;
  2073. }
  2074. step = 8 + i * 10;
  2075. res.lstDefectBmp[i].Dispose();
  2076. dataRowlist.Add(new object[]{ defectInfo.uid,defectInfo.Code, defectInfo.PhotoIndex,defectInfo.Name,
  2077. defectInfo.CentreX, defectInfo.CentreY / 100,defectInfo.Width * 10,defectInfo.Height * 10, defectInfo.Area * 100, defectInfo.ZXD, defectInfo.Contrast});
  2078. step = 9 + i * 10;
  2079. //告警判断???在此还是在收到新照片时触发???
  2080. if (res.record.ProductInfo.DefectAreaLimit > 0 && defectInfo.Area >= res.record.ProductInfo.DefectAreaLimit)
  2081. {
  2082. Log($"告警", $"瑕疵面积达到阈值!({defectInfo.Area}>={res.record.ProductInfo.DefectAreaLimit})", WarningEnum.High);
  2083. }
  2084. //必要瑕疵警告
  2085. if (res.record.ProductInfo.DefectAreaLimit > 0 )
  2086. {
  2087. string[] warnlabels = res.record.ProductInfo.WarnDefect.Split(',');
  2088. var haveLabel = warnlabels.ToList().Find(ft => ft == defectNameInfo.Value<string>("name"));
  2089. if (!string.IsNullOrEmpty(haveLabel))
  2090. {
  2091. Log($"告警", $"出现必须报警瑕疵-{haveLabel}", WarningEnum.High);
  2092. }
  2093. }
  2094. }
  2095. time += $"->打标小图保存({stopWatch.ElapsedMilliseconds})";
  2096. //有瑕疵打标图必需保存 Jpeg
  2097. dirPath = Util.CreateSubDir(confMgr.SysConfigParams.DefectSplicImag.SavePath, new List<string> { $"{res.record.BarCode}_{res.record.BarCodeName}" });
  2098. if (confMgr.SysConfigParams.DefectSplicImag.AutoSave)//保存瑕疵图
  2099. {
  2100. AddImageSave($"{dirPath}{res.photoIndex}_tag.jpg", res.bmpTag);
  2101. AddImageSave($"{dirPath}{res.photoIndex}_src.bmp", res.bmp);
  2102. //OpenCvSharp.Extensions.BitmapConverter.ToBitmap(res.bmpTag).Save($"{dirPath}{res.photoIndex}_tag.jpg", ImageFormat.Jpeg);
  2103. //OpenCvSharp.Extensions.BitmapConverter.ToBitmap(res.bmp).Save($"{dirPath}{res.photoIndex}_src.bmp", ImageFormat.Bmp);
  2104. }
  2105. time += $"->瑕疵图保存({stopWatch.ElapsedMilliseconds})";
  2106. //Log($"检测完成", "更新UI", WarningEnum.Normal, false);
  2107. //更新UI
  2108. int bmpHeight = res.bmp.Height;
  2109. //显示图片
  2110. //OnAutoRuning(new RunEventArgs(defectInfo.image));
  2111. //显示瑕疵图
  2112. OnAutoRuning(new RunEventArgs(dataRowlist));
  2113. step = 9;
  2114. //Log($"检测完成", "保存CSV", WarningEnum.Normal, false);
  2115. //保存CSV
  2116. dirPath = Util.CreateSubDir(confMgr.SysConfigParams.DefectSplicImag.SavePath, new List<string> { $"{res.record.BarCode}_{res.record.BarCodeName}" });
  2117. //bool b = Utils.ExcelUtil.DataTable2CSV($"{dirPath}{res.photoIndex}.csv", res.excelTable);
  2118. AddImageSave($"{dirPath}{res.photoIndex}.csv", res.excelTable);
  2119. //AddTextEvent(DateTime.Now,$"打标完成", $"{res.tag}.xlsx {(b ? "保存成功!" : "保存失败!")}");
  2120. step = 10;
  2121. time += $"->CSV保存({stopWatch.ElapsedMilliseconds})";
  2122. //每百米告警判断???在此还是在收到新照片时触发???
  2123. if (res.record.ProductInfo.DefectCountLimit > 0 && res.record.DefectTotalCount >= res.record.ProductInfo.DefectCountLimit)
  2124. {
  2125. //每x米判定所有缺陷数量
  2126. if (res.record.ProductInfo.DefectCntLength > 0)
  2127. {
  2128. int compLen = (int)res.record.ProductInfo.DefectCntLength * 100;//每百米 to cm
  2129. int compCount = compLen * confMgr.SysConfigParams.Cm2px_y / res.bmp.Height;
  2130. //从上次告警后重新开始计算长度及数量
  2131. int defectCount = res.record.DefectInfoList.Where(m => m.PhotoIndex >= res.record.preWarningPhotoIndex && m.PhotoIndex >= res.photoIndex + 1 - compCount).Count();
  2132. if (defectCount >= res.record.ProductInfo.DefectCountLimit)
  2133. {
  2134. res.record.preWarningPhotoIndex = res.photoIndex + 1;
  2135. Log($"告警", $"每{Math.Round(res.record.ProductInfo.DefectCntLength, 2)}米瑕疵数量达到阈值!({defectCount}>={res.record.ProductInfo.DefectCountLimit})", WarningEnum.High);
  2136. }
  2137. }
  2138. step = 11;
  2139. //按缺陷计算没X米多少缺陷报警
  2140. for (int i = 0; i < res.record.ProductInfo.QualifiedLimitList.Count; i++)
  2141. {
  2142. var defectWarn = res.record.ProductInfo.QualifiedLimitList[i];
  2143. if (defectWarn.DefectWarnLength > 0 || defectWarn.DefectWarnCnt > 0)
  2144. {
  2145. step = 12;
  2146. int warnLen = defectWarn.DefectWarnLength * 100;//每百米 to cm
  2147. int warnCount = warnLen * confMgr.SysConfigParams.Cm2px_y / res.bmp.Height;
  2148. //从上次告警后重新开始计算长度及数量
  2149. int warnDefectCount = res.record.DefectInfoList.Where(m => m.PhotoIndex >= res.record.preWarningPhotoIndexByLabel[i] && m.PhotoIndex >= res.photoIndex + 1 - warnCount).Count();
  2150. if (warnDefectCount >= defectWarn.DefectWarnCnt)
  2151. {
  2152. res.record.preWarningPhotoIndexByLabel[i] = res.photoIndex + 1;
  2153. Log($"告警", $"每{defectWarn.DefectWarnLength}米{GetDefectName(defectWarn.Code)}瑕疵数量达到阈值!({warnDefectCount}>={defectWarn.DefectWarnCnt})", WarningEnum.High);
  2154. }
  2155. }
  2156. }
  2157. }
  2158. time += $"->告警判定({stopWatch.ElapsedMilliseconds})";
  2159. }
  2160. }
  2161. else
  2162. {
  2163. Log($"打标失败", $"(图像{res.photoIndex})-瑕疵检测失败", WarningEnum.Low);
  2164. }
  2165. time += $"->完成处理({stopWatch.ElapsedMilliseconds})";
  2166. Log($"检测完成2", time, WarningEnum.Normal, false);
  2167. res.bmp.Dispose();
  2168. res.bmpTag.Dispose();
  2169. res.bmps_cut = null;
  2170. res.excelTable.Dispose();
  2171. }
  2172. catch (Exception ex)
  2173. {
  2174. Log($"打标失败", $"(图像{res.photoIndex})-瑕疵检测异常({step}):{ex.Message}");
  2175. }
  2176. finally
  2177. {
  2178. res.record.ScannerPhotoFinishCount++;
  2179. int liScannerPhotoFinishCount = res.record.ScannerPhotoFinishCount;
  2180. int liScannerPhotoCount = res.record.ScannerPhotoCount;
  2181. //Log($"检测完成", $"{liScannerPhotoFinishCount}/{liScannerPhotoCount}", WarningEnum.Normal, false);
  2182. //this.BeginInvoke(new System.Action(() =>
  2183. //{
  2184. // this.lblWaitImageCount.Text = $"{liScannerPhotoCount - liScannerPhotoFinishCount}";
  2185. //}));
  2186. res = null;
  2187. System.GC.Collect();
  2188. }
  2189. }
  2190. }
  2191. #endregion
  2192. #region 图片存储
  2193. private class SaveImgInfo
  2194. {
  2195. public string Path { get; set; }
  2196. public Mat Img { get; set; }
  2197. public DataTable DataTable { get; set; }
  2198. }
  2199. private ConcurrentQueue<SaveImgInfo> _SaveImgQueue = new ConcurrentQueue<SaveImgInfo>();
  2200. private void AddImageSave(string path, Mat img)
  2201. {
  2202. _SaveImgQueue.Enqueue(new SaveImgInfo { Path = path, Img = img.Clone() });
  2203. //Thread.Sleep(10);
  2204. if (_SaveImgQueue.Count > 100)
  2205. {
  2206. SaveImgInfo saveImgInfo;
  2207. _SaveImgQueue.TryDequeue(out saveImgInfo);
  2208. if (saveImgInfo.Img != null)
  2209. {
  2210. saveImgInfo.Img.Dispose();
  2211. saveImgInfo.Img = null;
  2212. System.GC.Collect();
  2213. }
  2214. Log("存图警告", "存图超限-出队", WarningEnum.Low);
  2215. }
  2216. }
  2217. private void AddImageSave(string path, DataTable dt)
  2218. {
  2219. _SaveImgQueue.Enqueue(new SaveImgInfo { Path = path, Img = null, DataTable = dt.Clone() });
  2220. }
  2221. /// <summary>
  2222. /// 图片存储
  2223. /// </summary>
  2224. private void SaveImgThreadFunction()
  2225. {
  2226. while (true)
  2227. {
  2228. try
  2229. {
  2230. if (_cts.IsCancellationRequested)
  2231. break;
  2232. SaveImgInfo saveImgInfo;
  2233. if (_SaveImgQueue.TryDequeue(out saveImgInfo))
  2234. {
  2235. if(saveImgInfo.Img != null)
  2236. {
  2237. saveImgInfo.Img.ImWrite(saveImgInfo.Path);
  2238. //OpenCvSharp.Extensions.BitmapConverter.ToBitmap(res.lstDefectBmp[i]).Save(filename, ImageFormat.Jpeg);
  2239. saveImgInfo.Img.Dispose();
  2240. saveImgInfo.Img = null;
  2241. }
  2242. else
  2243. {
  2244. if(!string.IsNullOrEmpty(saveImgInfo.Path))
  2245. {
  2246. bool b = Utils.ExcelUtil.DataTable2CSV(saveImgInfo.Path, saveImgInfo.DataTable);
  2247. }
  2248. }
  2249. //System.GC.Collect();
  2250. }
  2251. #region 堆积显示
  2252. OnAutoRuning(new RunEventArgs(0, 0, _SaveImgQueue.Count));
  2253. //处理多余
  2254. if(_SaveImgQueue.Count > 100)
  2255. {
  2256. _SaveImgQueue.TryDequeue(out saveImgInfo);
  2257. if (saveImgInfo.Img != null)
  2258. {
  2259. saveImgInfo.Img.Dispose();
  2260. saveImgInfo.Img = null;
  2261. System.GC.Collect();
  2262. }
  2263. Log("存图警告", "存图超限-紧急出队", WarningEnum.Low);
  2264. }
  2265. #endregion
  2266. Thread.Sleep(20);
  2267. }
  2268. catch (Exception e)
  2269. {
  2270. Log("存图报警", "存图出错:" + e.Message + "\n", WarningEnum.High);
  2271. }
  2272. }
  2273. }
  2274. #endregion
  2275. #region 结束验布
  2276. public bool Stop()
  2277. {
  2278. if (confMgr.SysConfigParams.OpenPLC)
  2279. {
  2280. if (plcDev.IsInit())
  2281. {
  2282. plcDev.WriteCoil("DB3.DBX0.0", false);//zt
  2283. plcDev.WriteCoil("DB3.DBX0.1", true);
  2284. }
  2285. else
  2286. {
  2287. Log("运行", "PLC连接异常!", WarningEnum.High);
  2288. return false;
  2289. }
  2290. }
  2291. else if (confMgr.SysConfigParams.OpenIO)
  2292. {
  2293. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.停止), GetIOBitIndex((int)DOName.停止), true);
  2294. Task.Run(async () =>
  2295. {
  2296. await Task.Delay(500);
  2297. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.停止), GetIOBitIndex((int)DOName.停止), false);
  2298. });
  2299. }
  2300. return true;
  2301. }
  2302. public bool DefectEnd(Form fatherFrm)
  2303. {
  2304. Log("结束验布", "结束验布!");
  2305. Stop();
  2306. Thread.Sleep(500);
  2307. //CurrentState = CurrentStateEnum.初始;
  2308. _isRuning = false;
  2309. _isAuto = false;
  2310. OnAutoRuning(new RunEventArgs(_isAuto));
  2311. Thread.Sleep(500);
  2312. pStopWatch.Stop();
  2313. pRunSpeedWatch.Stop();
  2314. if (currKey > 0 )
  2315. {
  2316. if (FrmDialog.ShowDialog(fatherFrm, $"是否保存当前检测结果?", "提示", true) == DialogResult.OK)
  2317. {
  2318. //Log("验布数据", "等待处理完成!");
  2319. //while(_matList1.Count >0 && _matList2.Count>0)
  2320. // Thread.Sleep(200);
  2321. //Log("验布数据", "处理完成!");
  2322. string szBatchId, szReelId;
  2323. double ldErpLen;
  2324. //szBatchId = ;
  2325. //szReelId = txtReelId.Text.Trim();
  2326. //ldErpLen = numErpLen.IsEmpty ? 0 : Convert.ToDouble(numErpLen.Text.Trim());
  2327. int myKey = currKey;
  2328. //Task.Run(() => { saveCurrRecord(myKey); });
  2329. saveCurrRecord(myKey);
  2330. //resetUIValue();
  2331. currKey = 0;
  2332. //this.btnStart.Enabled = true;
  2333. //this.btnEnd.Enabled = this.btnPause.Enabled = false;//这里有问题,应该是devPlc回调设置
  2334. }
  2335. else
  2336. {
  2337. Log("结束验布", "不保存数据结束验布!");
  2338. return false;
  2339. }
  2340. }
  2341. else
  2342. {
  2343. Log("结束验布", "无数据结束验布!");
  2344. _isDefect = false;
  2345. return false;
  2346. }
  2347. return true;
  2348. }
  2349. #endregion
  2350. #region IO解析
  2351. private int GetIOPortIndex(int DIDOEnum)
  2352. {
  2353. return DIDOEnum / 8;
  2354. }
  2355. private int GetIOBitIndex(int DIDOEnum)
  2356. {
  2357. return DIDOEnum % 8;
  2358. }
  2359. #endregion
  2360. #region 三色灯
  2361. /// <summary>
  2362. /// 三色灯初始化
  2363. /// </summary>
  2364. public void LedReady()
  2365. {
  2366. if (confMgr.SysConfigParams.OpenIO && _isOpenIO)
  2367. {
  2368. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯绿灯), GetIOBitIndex((int)DOName.三色灯绿灯), false);
  2369. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯黄灯), GetIOBitIndex((int)DOName.三色灯黄灯), false);
  2370. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯红灯), GetIOBitIndex((int)DOName.三色灯红灯), false);
  2371. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯蜂鸣器), GetIOBitIndex((int)DOName.三色灯蜂鸣器), false);
  2372. }
  2373. }
  2374. /// <summary>
  2375. /// 运行状态三色灯
  2376. /// </summary>
  2377. public void LedRun()
  2378. {
  2379. if (confMgr.SysConfigParams.OpenIO && _isOpenIO)
  2380. {
  2381. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯绿灯), GetIOBitIndex((int)DOName.三色灯绿灯), true);
  2382. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯黄灯), GetIOBitIndex((int)DOName.三色灯黄灯), false);
  2383. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯红灯), GetIOBitIndex((int)DOName.三色灯红灯), false);
  2384. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯蜂鸣器), GetIOBitIndex((int)DOName.三色灯蜂鸣器), false);
  2385. }
  2386. }
  2387. /// <summary>
  2388. /// 暂停状态三色灯
  2389. /// </summary>
  2390. public void LedPause()
  2391. {
  2392. if (confMgr.SysConfigParams.OpenIO && _isOpenIO)
  2393. {
  2394. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯绿灯), GetIOBitIndex((int)DOName.三色灯绿灯), false);
  2395. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯黄灯), GetIOBitIndex((int)DOName.三色灯黄灯), false);
  2396. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯红灯), GetIOBitIndex((int)DOName.三色灯红灯), true);
  2397. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯蜂鸣器), GetIOBitIndex((int)DOName.三色灯蜂鸣器), false);
  2398. }
  2399. }
  2400. //控制黄灯闪烁
  2401. private bool Blink;
  2402. private int BlinkCnt = 0;
  2403. //控制蜂鸣间隔
  2404. private int BuzzCnt = 0;
  2405. /// <summary>
  2406. /// 回原状态三色灯
  2407. /// </summary>
  2408. /// <param name="val"></param>
  2409. public void LedRset(bool val)
  2410. {
  2411. if (confMgr.SysConfigParams.OpenIO && _isOpenIO)
  2412. {
  2413. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯绿灯), GetIOBitIndex((int)DOName.三色灯绿灯), false);
  2414. //ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯黄灯), GetIOBitIndex((int)DOName.三色灯黄灯), val);
  2415. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯红灯), GetIOBitIndex((int)DOName.三色灯红灯), false);
  2416. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯蜂鸣器), GetIOBitIndex((int)DOName.三色灯蜂鸣器), false);
  2417. Blink = val;
  2418. BlinkCnt = 0;
  2419. }
  2420. }
  2421. #endregion
  2422. #region 报警等、按钮IO
  2423. /// <summary>
  2424. /// 三色灯报警状态显示
  2425. /// </summary>
  2426. /// <returns></returns>
  2427. public bool WarningShowLed(bool DisEnableBuzz)
  2428. {
  2429. bool sts = false;
  2430. if (statusMgr.Warning == WarningEnum.Normal)
  2431. {
  2432. if (confMgr.SysConfigParams.OpenIO && _isOpenIO)
  2433. {
  2434. if (statusMgr.Status == SystemStsEnum.Auto)
  2435. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯绿灯), GetIOBitIndex((int)DOName.三色灯绿灯), true);
  2436. else
  2437. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯绿灯), GetIOBitIndex((int)DOName.三色灯绿灯), false);
  2438. if (statusMgr.Status == SystemStsEnum.Pause)
  2439. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯红灯), GetIOBitIndex((int)DOName.三色灯红灯), true);
  2440. else
  2441. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯红灯), GetIOBitIndex((int)DOName.三色灯红灯), false);
  2442. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯蜂鸣器), GetIOBitIndex((int)DOName.三色灯蜂鸣器), false);
  2443. BuzzCnt = 0;
  2444. //判断黄灯是否需要闪烁,调用200ms一次
  2445. if (Blink)
  2446. {
  2447. if (BlinkCnt < 3)
  2448. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯黄灯), GetIOBitIndex((int)DOName.三色灯黄灯), true);
  2449. else if (BlinkCnt < 6)
  2450. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯黄灯), GetIOBitIndex((int)DOName.三色灯黄灯), false);
  2451. BlinkCnt++;
  2452. if (BlinkCnt == 6)
  2453. BlinkCnt = 0;
  2454. }
  2455. else
  2456. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯黄灯), GetIOBitIndex((int)DOName.三色灯黄灯), false);
  2457. }
  2458. }
  2459. if (statusMgr.Warning == WarningEnum.Low)
  2460. {
  2461. //ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.启动按钮绿灯), GetIOBitIndex((int)DOName.启动按钮绿灯), false);
  2462. //ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.停止按钮红灯), GetIOBitIndex((int)DOName.停止按钮红灯), true);
  2463. if (confMgr.SysConfigParams.OpenIO && _isOpenIO)
  2464. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯红灯), GetIOBitIndex((int)DOName.三色灯红灯), true);
  2465. //ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯绿灯), GetIOBitIndex((int)DOName.三色灯绿灯), false);
  2466. //sts = true;
  2467. }
  2468. if (statusMgr.Warning == WarningEnum.High)
  2469. {
  2470. //发送停止信号
  2471. Stop();
  2472. sts = true;
  2473. if (confMgr.SysConfigParams.OpenIO && _isOpenIO)
  2474. {
  2475. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯红灯), GetIOBitIndex((int)DOName.三色灯红灯), true);
  2476. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯绿灯), GetIOBitIndex((int)DOName.三色灯绿灯), false);
  2477. if (confMgr.SysConfigParams.OpenBuzzer && !DisEnableBuzz)
  2478. {
  2479. if (BuzzCnt < 3)
  2480. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯蜂鸣器), GetIOBitIndex((int)DOName.三色灯蜂鸣器), true);
  2481. else if (BuzzCnt < 6)
  2482. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.三色灯蜂鸣器), GetIOBitIndex((int)DOName.三色灯蜂鸣器), false);
  2483. BuzzCnt++;
  2484. if (BuzzCnt == 6)
  2485. BuzzCnt = 0;
  2486. }
  2487. }
  2488. }
  2489. return sts;
  2490. }
  2491. /// <summary>
  2492. /// 按钮IO检测
  2493. /// </summary>
  2494. /// <returns></returns>
  2495. public int ButtonIOTrg(bool DisEnableDoorAlm)
  2496. {
  2497. int ret = 0;
  2498. bool sts;
  2499. if (confMgr.SysConfigParams.OpenIO && _isOpenIO)
  2500. {
  2501. //if (confMgr.SysConfigParams.OpenDoor && !DisEnableDoorAlm)
  2502. //{
  2503. // ioCardDev.GetDIBitState(GetIOPortIndex((int)DIName.门磁), GetIOBitIndex((int)DIName.门磁), out sts);
  2504. // if ((!sts) && (statusMgr.Status == SystemStsEnum.Auto))
  2505. // {
  2506. // Log("暂停", "门磁报警-门打开", WarningEnum.Low);
  2507. // statusMgr.GotoPause();
  2508. // SendStatus();
  2509. // ret = 2;
  2510. // }
  2511. //}
  2512. ioCardDev.GetDIBitState(GetIOPortIndex((int)DIName.暂停按钮), GetIOBitIndex((int)DIName.暂停按钮), out sts);
  2513. if (sts)
  2514. {
  2515. Log("暂停", "手动暂停");
  2516. statusMgr.GotoPause();
  2517. SendStatus();
  2518. ret = 2;
  2519. }
  2520. ioCardDev.GetDIBitState(GetIOPortIndex((int)DIName.复位按钮), GetIOBitIndex((int)DIName.复位按钮), out sts);
  2521. if (sts)
  2522. {
  2523. ret = 3;
  2524. }
  2525. ioCardDev.GetDIBitState(GetIOPortIndex((int)DIName.启动按钮), GetIOBitIndex((int)DIName.启动按钮), out sts);
  2526. if (sts)
  2527. ret = 1;
  2528. }
  2529. return ret;
  2530. }
  2531. #endregion
  2532. #region 系统关闭
  2533. /// <summary>
  2534. /// 关闭
  2535. /// </summary>
  2536. public void Close()
  2537. {
  2538. _isInit = false;
  2539. _isRuning = false;
  2540. if (null != _cts)
  2541. {
  2542. _cts.Cancel();
  2543. }
  2544. if (null != _mainThread)
  2545. {
  2546. _mainThread.Join(1000);
  2547. }
  2548. if (null != _Cam1Thread)
  2549. {
  2550. _Cam1Thread.Join(1000);
  2551. }
  2552. if (null != _Cam2Thread)
  2553. {
  2554. _Cam2Thread.Join(1000);
  2555. }
  2556. if (null != _SpeedThread)
  2557. {
  2558. _SpeedThread.Join(1000);
  2559. }
  2560. if (null != _SaveImgThread)
  2561. {
  2562. _SaveImgThread.Join(1000);
  2563. }
  2564. //关闭计米器
  2565. if (confMgr.SysConfigParams.OpenLengthCount)
  2566. lengthCounter.Close();
  2567. //关闭相机
  2568. LineCamDev1.CloseCamera();
  2569. LineCamDev2.CloseCamera();
  2570. //关闭光源
  2571. for (int i = 0; i < LightChCount; i++)
  2572. {
  2573. lightDev.CloseLight(i + 1);
  2574. }
  2575. lightDev.CloseDev();
  2576. //关闭io
  2577. if (confMgr.SysConfigParams.OpenIO)
  2578. {
  2579. ioCardDev.ResetAllDO();
  2580. ioCardDev.CloseBoard();
  2581. }
  2582. if (confMgr.SysConfigParams.OpenPLC)
  2583. plcDev.CloseDev();
  2584. }
  2585. #endregion
  2586. #region 日志报警
  2587. /// <summary>
  2588. /// 初始化记录报警和显示
  2589. /// </summary>
  2590. /// <param name="tag">标头</param>
  2591. /// <param name="msg">内容</param>
  2592. /// <param name="warning">报警状态</param>
  2593. private void InitLog(string msg, string tag = "初始化", WarningEnum warning = WarningEnum.Normal)
  2594. {
  2595. OnInitRuning(new InitEventArgs(msg));
  2596. statusMgr.GotoWarning(warning, tag, msg);
  2597. }
  2598. /// <summary>
  2599. /// 记录报警和显示
  2600. /// </summary>
  2601. /// <param name="tag">标头</param>
  2602. /// <param name="msg">内容</param>
  2603. /// <param name="warning">报警状态</param>
  2604. private void Log(string tag, string msg, WarningEnum warning = WarningEnum.Normal, bool show = true)
  2605. {
  2606. if(show)
  2607. OnMainRuning(new MainEventArgs(tag, msg, warning));
  2608. statusMgr.GotoWarning(warning, tag, msg);
  2609. //开启云端
  2610. if ((init_Cloud) && (warning != WarningEnum.Normal))
  2611. {
  2612. //上传报警状态和信息
  2613. string statusStr = warning == WarningEnum.Normal ? "正常" : warning == WarningEnum.Low ? "警告" : "系统报警";
  2614. cloudMgr.SendTopic("device/attributes", $"{{\"status\": \"{statusStr}\", \"alm\": \"{tag}-{msg}\", " +
  2615. $"\"name\": \"{confMgr.SysConfigParams.CloudThisName}\", \"DailyOutput\": \"{DailyOutput}\"}}");
  2616. }
  2617. }
  2618. #endregion
  2619. #region 硬件
  2620. #region 硬件型号配置
  2621. public LightDevNameEnum SysUseLight = LightDevNameEnum.CST;
  2622. #endregion
  2623. #region 硬件字段
  2624. private CamDev _LinecamDev1;
  2625. /// <summary>
  2626. /// io控制卡
  2627. /// </summary>
  2628. public CamDev LineCamDev1 { get { return _LinecamDev1; } }
  2629. private CamDev _LinecamDev2;
  2630. /// <summary>
  2631. /// io控制卡
  2632. /// </summary>
  2633. public CamDev LineCamDev2 { get { return _LinecamDev2; } }
  2634. private IOCardDev ioCardDev;
  2635. /// <summary>
  2636. /// io控制卡
  2637. /// </summary>
  2638. public IOCardDev IOCardDev { get { return ioCardDev; } }
  2639. private LightDev lightDev;
  2640. /// <summary>
  2641. /// 光源控制
  2642. /// </summary>
  2643. public LightDev LightDev { get { return lightDev; } }
  2644. public string LightName { get { return "Light"; } }
  2645. public int LightChCount = 1;//美尚4通道,其他6通道
  2646. /// <summary>
  2647. /// 计米器
  2648. /// </summary>
  2649. public SerialPort LengthCounterPort { get { return lengthCounter; } }
  2650. private SerialPort lengthCounter;
  2651. private PlcDev plcDev;
  2652. /// <summary>
  2653. /// PLC控制
  2654. /// </summary>
  2655. public PlcDev PlcDev { get { return plcDev; } }
  2656. private PrintControl printControl;
  2657. /// <summary>
  2658. /// 打印机模块
  2659. /// </summary>
  2660. public PrintControl PrintControl { get { return printControl; } }
  2661. #endregion
  2662. #region 初始化和基本电机IO操作
  2663. private void InitDev()
  2664. {
  2665. ioCardDev = new AdvantechIO();
  2666. //CpuType.S71200 = 30
  2667. plcDev = new PlcDev(CpuType.S71200, confMgr.SysConfigParams.PLC_IP, (short)confMgr.SysConfigParams.PLC_Rack, (short)confMgr.SysConfigParams.PLC_Solt);
  2668. _LinecamDev1 = new CamDev(CameraEnumType.IKap, confMgr.SysConfigParams.CamIndex_1.ToString(), confMgr.SysConfigParams.CamPath_1, confMgr.SysConfigParams.CamDev_1);
  2669. _LinecamDev2 = new CamDev(CameraEnumType.IKap, confMgr.SysConfigParams.CamIndex_2.ToString(), confMgr.SysConfigParams.CamPath_2, confMgr.SysConfigParams.CamDev_2);
  2670. if (SysUseLight == LightDevNameEnum.CST)
  2671. lightDev = new CSTLight(LightName, LightChCount);
  2672. else
  2673. lightDev = new RseeLight(SysUseLight, LightName);
  2674. lengthCounter = new SerialPort(confMgr.SysConfigParams.LengthCounterCom, confMgr.SysConfigParams.LengthCounterComBaud);
  2675. }
  2676. /// <summary>
  2677. /// 初始化硬件
  2678. /// </summary>
  2679. /// <returns></returns>
  2680. private bool InitAllDev()
  2681. {
  2682. bool ret = false;
  2683. InitDev();
  2684. #if Online
  2685. //打印机模块初始化
  2686. //InitLog("打印机模块初始化...");
  2687. //try
  2688. //{
  2689. // printControl = new PrintControl();
  2690. // InitLog("初始化打印机模块成功!");
  2691. //}
  2692. //catch (Exception ex)
  2693. //{
  2694. // printControl = null;
  2695. // InitLog($"初始化打印机模块失败! {ex.Message}");
  2696. //}
  2697. if (confMgr.SysConfigParams.OpenLengthCount)
  2698. {
  2699. lengthCounter.Open();
  2700. if (!lengthCounter.IsOpen)
  2701. {
  2702. InitLog("计米器初始化失败!", "初始化", WarningEnum.High);
  2703. return ret;
  2704. }
  2705. InitLog("计米器初始化成功!");
  2706. }
  2707. if (confMgr.SysConfigParams.OpenPLC)
  2708. {
  2709. //PLC初始化
  2710. InitLog("PLC连接初始化...");
  2711. if(!plcDev.OpenDev())
  2712. {
  2713. InitLog("PLC连接初始化失败!", "初始化", WarningEnum.High);
  2714. return ret;
  2715. }
  2716. InitLog("PLC连接成功!");
  2717. }
  2718. _isOpenIO = false;
  2719. if (confMgr.SysConfigParams.OpenIO)
  2720. {
  2721. //IO初始化
  2722. InitLog("IO板卡初始化...");
  2723. if (ioCardDev.InitBoard(MaiMuControl.Device.IOBordType.Advantech) < 0)
  2724. {
  2725. InitLog("IO板卡初始化失败!", "初始化", WarningEnum.High);
  2726. return ret;
  2727. }
  2728. if (ioCardDev.OpenBoard(confMgr.SysConfigParams.IODevName, confMgr.SysConfigParams.IOCfgPath) < 0)
  2729. {
  2730. InitLog("打开IO板卡失败!", "初始化", WarningEnum.High);
  2731. return ret;
  2732. }
  2733. if (ioCardDev.ResetAllDO() < 0)
  2734. {
  2735. InitLog("IO Reset失败!", "初始化", WarningEnum.High);
  2736. return ret;
  2737. }
  2738. _isOpenIO = true;
  2739. InitLog("初始化IO板卡成功!");
  2740. }
  2741. //相机初始化
  2742. if(!_LinecamDev1.InitCamera())
  2743. {
  2744. InitLog("相机1初始化失败!", "初始化", WarningEnum.High);
  2745. return ret;
  2746. }
  2747. if(!_LinecamDev1.OpenCamera())
  2748. {
  2749. InitLog("相机1打开失败!", "初始化", WarningEnum.High);
  2750. return ret;
  2751. }
  2752. _LinecamDev1.IsMirrorX = confMgr.SysConfigParams.Cam1_flipX;
  2753. _LinecamDev1.IsMirrorY = confMgr.SysConfigParams.Cam1_flipY;
  2754. _LinecamDev1.WarningEvent = (level, msg) =>
  2755. {
  2756. Log($"相机1设备事件", msg, level);
  2757. };
  2758. if (!_LinecamDev2.InitCamera())
  2759. {
  2760. InitLog("相机2初始化失败!", "初始化", WarningEnum.High);
  2761. return ret;
  2762. }
  2763. if (!_LinecamDev2.OpenCamera())
  2764. {
  2765. InitLog("相机2打开失败!", "初始化", WarningEnum.High);
  2766. return ret;
  2767. }
  2768. _LinecamDev2.IsMirrorX = confMgr.SysConfigParams.Cam2_flipX;
  2769. _LinecamDev2.IsMirrorY = confMgr.SysConfigParams.Cam2_flipY;
  2770. _LinecamDev2.WarningEvent = (level, msg) =>
  2771. {
  2772. Log($"相机2设备事件", msg, level);
  2773. };
  2774. //光源初始化
  2775. InitLog("光源控制器初始化...");
  2776. int com_num = int.Parse(confMgr.SysConfigParams.LightCom.Remove(0, 3));
  2777. if (lightDev.InitDev(com_num, confMgr.SysConfigParams.LightComBaud) < 0)
  2778. {
  2779. InitLog("光源控制器初始化失败!", "初始化", WarningEnum.High);
  2780. return ret;
  2781. }
  2782. InitLog("初始化光源控制器成功!");
  2783. //关闭光源
  2784. for (int i = 0; i < LightChCount; i++)
  2785. {
  2786. lightDev.CloseLight(i + 1);
  2787. }
  2788. #endif
  2789. ret = true;
  2790. return ret;
  2791. }
  2792. /// <summary>
  2793. /// 读取硬件配置
  2794. /// </summary>
  2795. private bool LoadDevConfig()
  2796. {
  2797. LightParams lightParams = new LightParams(LightName, LightChCount);
  2798. //LightChCount = 6;
  2799. //lightParams.DevName = LightName;
  2800. lightParams.ComName = confMgr.SysConfigParams.LightCom;
  2801. lightParams.Buad = confMgr.SysConfigParams.LightComBaud;
  2802. //lightParams.ChCount = LightChCount;
  2803. lightDev.WriteCfgInfo(confMgr.DevConfigPath, lightParams);
  2804. return true;
  2805. }
  2806. #endregion
  2807. #endregion
  2808. #region 硬盘检测
  2809. public static bool CheckDisk(IWin32Window owner, int max = 10)
  2810. {
  2811. if (!string.IsNullOrEmpty(ConfMgr.Instance.SysConfigParams.DefectSrcImag.SavePath))
  2812. {
  2813. string path = ConfMgr.Instance.SysConfigParams.DefectSrcImag.SavePath;
  2814. string volume = path.Substring(0, path.IndexOf(':'));
  2815. long freespace = DiskAPI.GetHardDiskSpace(volume);
  2816. if (freespace < max)
  2817. {
  2818. string tip = $"当前{volume}硬盘容量:{freespace}GB,小于{max}GB。注意清理!!";
  2819. FrmDialog.ShowDialog(owner, tip, "警告", true);
  2820. return false;
  2821. }
  2822. }
  2823. return true;
  2824. }
  2825. #endregion
  2826. #region 初始化事件
  2827. /// <summary>
  2828. /// 初始化回调
  2829. /// </summary>
  2830. /// <param name="sender"></param>
  2831. /// <param name="e"></param>
  2832. public delegate void InitEventHandler(Object sender, InitEventArgs e);
  2833. public event InitEventHandler InitRuning;
  2834. protected virtual void OnInitRuning(InitEventArgs e)
  2835. {
  2836. if (null != InitRuning)
  2837. {
  2838. InitRuning(this, e);
  2839. }
  2840. }
  2841. #endregion
  2842. #region 主窗体显示事件
  2843. /// <summary>
  2844. /// 主窗体回调
  2845. /// </summary>
  2846. /// <param name="sender"></param>
  2847. /// <param name="e"></param>
  2848. public delegate void MainEventHandler(Object sender, MainEventArgs e);
  2849. public event MainEventHandler MainRuning;
  2850. protected virtual void OnMainRuning(MainEventArgs e)
  2851. {
  2852. if (null != MainRuning)
  2853. {
  2854. MainRuning(this, e);
  2855. }
  2856. }
  2857. /// <summary>
  2858. /// 流程回调
  2859. /// </summary>
  2860. /// <param name="sender"></param>
  2861. /// <param name="e"></param>
  2862. public delegate void RunEventHandler(Object sender, RunEventArgs e);
  2863. public event RunEventHandler AutoRuning;
  2864. protected virtual void OnAutoRuning(RunEventArgs e)
  2865. {
  2866. if (null != AutoRuning)
  2867. {
  2868. AutoRuning(this, e);
  2869. }
  2870. }
  2871. #endregion
  2872. #region 加载测试列表
  2873. /// <summary>
  2874. /// 加载产品列表
  2875. /// </summary>
  2876. public void LoadProductCodeList()
  2877. {
  2878. try
  2879. {
  2880. productCodeList = PdtService.GetListNav().Select(m => m.Name).ToList();
  2881. productIdList = PdtService.GetListNav().Select(m => m.Id).ToList();
  2882. }
  2883. catch (Exception ex)
  2884. {
  2885. OnMainRuning(new MainEventArgs("启动", "加载检测标准失败:" + ex.Message, WarningEnum.High));
  2886. statusMgr.GotoWarning(WarningEnum.High, "启动", "加载检测标准失败:" + ex.Message);
  2887. SendStatus();
  2888. }
  2889. }
  2890. #endregion
  2891. #region 界面显示
  2892. public static void showRowNum_onDataGrid_RowPostPaint(DataGridView dgv, object sender, DataGridViewRowPostPaintEventArgs e)
  2893. {
  2894. Rectangle rectangle = new Rectangle(e.RowBounds.Location.X, e.RowBounds.Location.Y, dgv.RowHeadersWidth - 4, e.RowBounds.Height);
  2895. TextRenderer.DrawText(e.Graphics, (e.RowIndex + 1).ToString(), dgv.RowHeadersDefaultCellStyle.Font, rectangle, dgv.RowHeadersDefaultCellStyle.ForeColor, TextFormatFlags.VerticalCenter | TextFormatFlags.Right);
  2896. }
  2897. /// <summary>
  2898. /// IO二进制数据格式化到8位 XXXX10X0
  2899. /// </summary>
  2900. /// <param name="datas"></param>
  2901. /// <returns></returns>
  2902. public static string[] IODataFormatBinaryStr(string[] datas, bool clone, char defaultPadChar = 'X')
  2903. {
  2904. string[] datas2 = new string[datas.Length];
  2905. for (int i = 0; i < datas.Length; i++)
  2906. {
  2907. if (clone)
  2908. {
  2909. datas2[i] = datas[i].Replace(" ", "");
  2910. if (datas2[i].Length > 8)
  2911. datas2[i] = datas2[i].Substring(datas2[i].Length - 8);
  2912. else if (datas2[i].Length < 8)
  2913. datas2[i] = datas2[i].PadLeft(8, defaultPadChar);
  2914. }
  2915. else
  2916. {
  2917. datas[i] = datas[i].Replace(" ", "");
  2918. if (datas[i].Length > 8)
  2919. datas[i] = datas[i].Substring(datas[i].Length - 8);
  2920. else if (datas[i].Length < 8)
  2921. datas[i] = datas[i].PadLeft(8, defaultPadChar);
  2922. datas2 = datas;
  2923. }
  2924. }
  2925. return datas2;
  2926. }
  2927. /// <summary>
  2928. ///
  2929. /// </summary>
  2930. /// <param name="op_show_list">[XXHL XXXX,XXXX XXXX,...]</param>
  2931. /// <param name="currIoDatas">[byte,byte,byte,byte]</param>
  2932. /// <returns></returns>
  2933. public static bool compareIOInput(string[] op_show_list, byte[] currIoDatas)
  2934. {
  2935. int isok = 0;//1-true 2-false
  2936. string IN_OP_SHOW;
  2937. for (int i = 0; i < currIoDatas.Length; i++)
  2938. {
  2939. IN_OP_SHOW = op_show_list[i].Replace(" ", "").PadLeft(8, 'X');
  2940. if (IN_OP_SHOW.IndexOf('H') < 0 && IN_OP_SHOW.IndexOf('L') < 0)
  2941. continue;
  2942. for (int j = 7; j >= 0; j--)
  2943. {
  2944. byte bit = (byte)(1 << 7 - j);
  2945. if (IN_OP_SHOW[j] == 'H')
  2946. {
  2947. if ((bit & currIoDatas[i]) > 0)
  2948. isok = 1;
  2949. else
  2950. {
  2951. isok = 2;
  2952. break;
  2953. }
  2954. }
  2955. else if (IN_OP_SHOW[j] == 'L')
  2956. {
  2957. if ((currIoDatas[i] ^ (currIoDatas[i] | bit)) > 0)
  2958. isok = 1;
  2959. else
  2960. {
  2961. isok = 2;
  2962. break;
  2963. }
  2964. }
  2965. }
  2966. //已经不符
  2967. if (isok == 2) break;
  2968. }
  2969. //
  2970. return isok == 1;
  2971. }
  2972. #endregion
  2973. #region 启动
  2974. public bool StartMotion()
  2975. {
  2976. if (confMgr.SysConfigParams.OpenAutoRun)
  2977. {
  2978. Log("启动", "下发启动指令...");
  2979. if (confMgr.SysConfigParams.OpenPLC)
  2980. {
  2981. if (plcDev.IsInit())
  2982. {
  2983. plcDev.WriteCoil("DB3.DBX0.1", false);
  2984. plcDev.WriteCoil("DB3.DBX0.0", true);//启动
  2985. }
  2986. else
  2987. {
  2988. Log("运行", "PLC连接异常!", WarningEnum.High);
  2989. return false;
  2990. }
  2991. }
  2992. else if (confMgr.SysConfigParams.OpenIO)
  2993. {
  2994. bool sts;
  2995. ioCardDev.GetDIBitState(GetIOPortIndex((int)DIName.暂停按钮), GetIOBitIndex((int)DIName.暂停按钮), out sts);
  2996. if (!sts)
  2997. {
  2998. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.启动), GetIOBitIndex((int)DOName.启动), true);
  2999. Task.Run(async () =>
  3000. {
  3001. await Task.Delay(500);
  3002. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.启动), GetIOBitIndex((int)DOName.启动), false);
  3003. });
  3004. }
  3005. else
  3006. Log("运行", "存在暂停信号!", WarningEnum.Low);
  3007. }
  3008. }
  3009. else
  3010. Log("启动", "检测流程开启...");
  3011. return true;
  3012. }
  3013. /// <summary>
  3014. /// 加载ERP数据库数据
  3015. /// </summary>
  3016. /// <param name="barCode"></param>
  3017. /// <returns></returns>
  3018. private DataRow loadErpData(string barCode)
  3019. {
  3020. var paramList = new List<SugarParameter>() {
  3021. new SugarParameter("@code", barCode)
  3022. };
  3023. Stopwatch stopwatch = Stopwatch.StartNew();
  3024. var data = confMgr.execSql(confMgr.SysConfigParams.ErpSql, paramList);
  3025. if (data != null && data.Rows.Count < 1)
  3026. {
  3027. Log("Erp查询结果", $"{barCode}: 时长={stopwatch.ElapsedMilliseconds}ms, 无数据!", WarningEnum.Normal);
  3028. return null;
  3029. }
  3030. Log("Erp查询结果", $"{barCode}: 时长={stopwatch.ElapsedMilliseconds}ms, {JsonConvert.SerializeObject(data.Rows[0])}", WarningEnum.Normal);
  3031. return data.Rows[0];
  3032. }
  3033. /// <summary>
  3034. /// 自动运行
  3035. /// </summary>
  3036. /// <returns></returns>
  3037. public bool StartRun(Form fatherFrm, string sn, ref string DefectName, ref string name, ref string batch, ref string reel, ref string cnt)
  3038. {
  3039. bool ret = true;
  3040. _FatherFrm = fatherFrm;
  3041. string barCodeName = "", len = "0", batchId = "", reelId = "";
  3042. if(string.IsNullOrEmpty(name))
  3043. name = "未找到";
  3044. //运行前清除过期图片文件
  3045. //DateTime st = DateTime.Now;
  3046. DelectPictureFile();
  3047. if ((statusMgr.Status != SystemStsEnum.Standby) && (statusMgr.Status != SystemStsEnum.Pause))
  3048. {
  3049. Log("运行", "系统非可运行状态", WarningEnum.Low);
  3050. return false;
  3051. }
  3052. if (string.IsNullOrEmpty(sn))
  3053. {
  3054. Log("运行", "产品条码为空!", WarningEnum.Low);
  3055. return false;
  3056. }
  3057. //禾欣数据 sn,长度数量, 批号, 卷号
  3058. if (!string.IsNullOrWhiteSpace(confMgr.SysConfigParams.ErpDBConStr) && !string.IsNullOrWhiteSpace(confMgr.SysConfigParams.ErpSql) && !string.IsNullOrWhiteSpace(sn))
  3059. {
  3060. Log("扫码", $"产品条码({sn})到ERP查询对应数据...", WarningEnum.Normal);
  3061. var rowData = this.loadErpData(sn);
  3062. if (rowData == null)
  3063. {
  3064. Log("扫码", $"产品条码({sn})无对应ERP数据,不做响应!", WarningEnum.High);
  3065. return false;
  3066. }
  3067. barCodeName = rowData[0].ToString();
  3068. if (rowData.ItemArray.Length > 1) len = rowData[1].ToString();
  3069. if (rowData.ItemArray.Length > 2) batchId = rowData[2].ToString();
  3070. if (rowData.ItemArray.Length > 3) reelId = rowData[3].ToString();
  3071. }
  3072. else
  3073. barCodeName = sn;//没有ERP对应关系时直接使用条码做为品名
  3074. //Log("调试", $"time1:{(DateTime.Now - st).Milliseconds}");
  3075. //st = DateTime.Now;
  3076. int errStep = 0;
  3077. try
  3078. {
  3079. Product model;
  3080. //禾欣客户使用
  3081. if(confMgr.SysConfigParams.CustomerName == "hexin")
  3082. {
  3083. errStep = 1;
  3084. //SHNY-PX-6-***
  3085. string[] codes = barCodeName.Split(new char[] { '-' });
  3086. if (codes.Length < 4)
  3087. {
  3088. Log("扫码", $"产品品名({barCodeName})格式错误,不做响应!", WarningEnum.Low);
  3089. return false;
  3090. }
  3091. errStep = 2;
  3092. //加载新产品
  3093. string pcode = "1-" + codes[2];
  3094. if (codes[1] == "0" || confMgr.SysConfigParams.SuedeList.Contains(codes[1]))
  3095. pcode = "0-" + codes[2];
  3096. model = PdtService.GetModelNav(pcode); //frmProduct.loadProduct(code);
  3097. name = barCodeName;
  3098. batch = batchId;
  3099. reel = reelId;
  3100. cnt = len;
  3101. }
  3102. else
  3103. {
  3104. if (string.IsNullOrEmpty(name) || name == "未找到")
  3105. {
  3106. Log("运行", "产品品名为空!", WarningEnum.Low);
  3107. return false;
  3108. }
  3109. if (string.IsNullOrEmpty(DefectName))
  3110. {
  3111. Log("运行", "检测标准未选择!", WarningEnum.Low);
  3112. return false;
  3113. }
  3114. //if (string.IsNullOrEmpty(batch))
  3115. //{
  3116. // Log("运行", "批号为空!", WarningEnum.Low);
  3117. // return false;
  3118. //}
  3119. //if (string.IsNullOrEmpty(reel))
  3120. //{
  3121. // Log("运行", "卷号为空!", WarningEnum.Low);
  3122. // return false;
  3123. //}
  3124. barCodeName = name;
  3125. batchId = batch;
  3126. reelId = reel;
  3127. double t;
  3128. cnt = double.TryParse(cnt, out t) ?cnt:"0";
  3129. model = PdtService.GetModelNavByName(DefectName);
  3130. }
  3131. if (model == null)
  3132. {
  3133. Log("扫码", $"编码({sn})对应配方不存在,请先添加产品配方设置,暂停设备!", WarningEnum.High);
  3134. return false;
  3135. }
  3136. DefectName = model.Name;
  3137. //数据处理
  3138. Records record;
  3139. lock (lockCurrKey)
  3140. {
  3141. errStep = 3;
  3142. //保存,这里队列图片可能还未检测完
  3143. if (currKey > 0)
  3144. {
  3145. string szBatchId, szReelId;
  3146. double ldErpLen;
  3147. szBatchId = batch;
  3148. szReelId = reel;
  3149. ldErpLen = Convert.ToDouble(cnt);
  3150. //BatchId = code,//code[2]
  3151. //ReelId = "1",//code[3]
  3152. int mykey = currKey;
  3153. //Task.Run(() => { saveCurrRecord(mykey); });
  3154. saveCurrRecord(mykey);
  3155. currKey = 0;
  3156. }
  3157. errStep = 4;
  3158. var now = DateTime.Now;
  3159. currKey = now.Hour * 10000 + now.Minute * 100 + now.Second;
  3160. //var materialItem = codes[0]+"-"+ codes[1];
  3161. //var colorItem = Config.getColorItem(int.Parse(codes[2]));
  3162. record = new Records()
  3163. {
  3164. currKey = currKey,
  3165. ProductId = model.Id,
  3166. ProductInfo = model,//后面计算合格时用
  3167. Color = model.ColorName,
  3168. Material = model.Material,//codes[0] + "-" + codes[1],// (materialItem == null ? "未知" : materialItem["name"].ToString()),
  3169. BarCode = sn,
  3170. BarCodeName = barCodeName,
  3171. ErpLen = double.Parse(len),
  3172. BatchId = batchId,
  3173. ReelId = reelId,
  3174. ModifyUserCode = userMgr.LoginUser.Code,
  3175. CreateUserCode = userMgr.LoginUser.Code,
  3176. };
  3177. htTask.Add(currKey, record);
  3178. }
  3179. errStep = 8;
  3180. //
  3181. errStep = 9;
  3182. Log("扫码", $"品名({barCodeName}),条码({sn}),加载产品信息({model.Code})完成,加载配方(光源={model.LightValue},曝光={model.ExposureTime},增益={model.Gain})...");
  3183. errStep = 10;
  3184. #if Online
  3185. if (model.LightValue > 0)//光源 - 通道0
  3186. lightDev.SetLightDigitalValue(1, model.LightValue);
  3187. errStep = 11;
  3188. if (model.ExposureTime > 0 || model.Gain > 0)//相机曝光 增益
  3189. {
  3190. LineCamDev1.SetExposure((float)(model.ExposureTime > 0 ? model.ExposureTime : 0));
  3191. LineCamDev1.SetGain((float)(model.Gain > 0 ? model.Gain : 0));
  3192. LineCamDev2.SetExposure((float)(model.ExposureTime > 0 ? model.ExposureTime : 0));
  3193. LineCamDev2.SetGain((float)(model.Gain > 0 ? model.Gain : 0));
  3194. }
  3195. #endif
  3196. errStep = 15;
  3197. Log("扫码", $"品名({barCodeName}),配方设置完成:光源={model.LightValue},曝光={model.ExposureTime}");
  3198. //显示二次判定项和打标项
  3199. OnAutoRuning(new RunEventArgs(model));
  3200. //加载所有二次判断
  3201. //显示光源亮度
  3202. OnAutoRuning(new RunEventArgs(model.LightValue));
  3203. //计米器清空
  3204. #if Online
  3205. ClearLengthCount();
  3206. #endif
  3207. JmFtStart = false;
  3208. Thread.Sleep(1000);
  3209. //启动ai寻边模型
  3210. if (confMgr.SysConfigParams.OpenAIEdge)
  3211. {
  3212. Log("加载", $"加载ai寻边模型");
  3213. OpencvUtils.LoadEdgeMode();
  3214. }
  3215. //清空相机内存
  3216. LineCamDev1.ClearImageQueue();
  3217. LineCamDev2.ClearImageQueue();
  3218. //if(LineCamDev1.ClearImageQueue())
  3219. //{
  3220. // Log("内存", $"相机1清空内存失败!", WarningEnum.High);
  3221. // return false;
  3222. //}
  3223. //if (LineCamDev2.ClearImageQueue())
  3224. //{
  3225. // Log("内存", $"相机2清空内存失败!", WarningEnum.High);
  3226. // return false;
  3227. //}
  3228. //电机启动
  3229. StartMotion();
  3230. pStopWatch.Restart();
  3231. pRunSpeedWatch.Restart();
  3232. //清空安全队列
  3233. ScanPhotoInfo tryDe;
  3234. while (_matList1.TryDequeue(out tryDe))
  3235. {
  3236. Thread.Sleep(10);
  3237. }
  3238. while (_matList2.TryDequeue(out tryDe))
  3239. {
  3240. Thread.Sleep(10);
  3241. }
  3242. _isHaveImgL = false;
  3243. _isHaveImgR = false;
  3244. _marginWidth1 = 0;
  3245. _marginWidth2 = 0;
  3246. Cam1Cnt = 0;
  3247. Cam2Cnt = 0;
  3248. defectPuaseList.Clear();
  3249. defectDBList.Clear();
  3250. defectPuaseImgList.Clear();
  3251. System.GC.Collect();
  3252. errStep = 16;
  3253. LedRun();
  3254. _isRuning = true;
  3255. _isAuto = true;
  3256. statusMgr.GotoAuto();
  3257. SendStatus();
  3258. CurrProductModel = model;
  3259. //获取模型label
  3260. GetDefectAllLabel();
  3261. }
  3262. catch (Exception ex)
  3263. {
  3264. Log("运行", $"程序错误-{errStep}:" + ex.Message + "\n", WarningEnum.High);
  3265. }
  3266. return ret;
  3267. }
  3268. /// <summary>
  3269. /// 暂停重启
  3270. /// </summary>
  3271. /// <returns></returns>
  3272. public bool ReStartRun()
  3273. {
  3274. bool ret = false;
  3275. Log("启动", "下发启动指令...");
  3276. if (confMgr.SysConfigParams.OpenPLC)
  3277. {
  3278. if (plcDev.IsInit())
  3279. {
  3280. plcDev.WriteCoil("DB3.DBX0.1", false);
  3281. plcDev.WriteCoil("DB3.DBX0.0", true);//启动
  3282. }
  3283. else
  3284. {
  3285. Log("运行", "PLC连接异常!", WarningEnum.High);
  3286. return false;
  3287. }
  3288. }
  3289. else if (confMgr.SysConfigParams.OpenIO)
  3290. {
  3291. bool sts;
  3292. ioCardDev.GetDIBitState(GetIOPortIndex((int)DIName.暂停按钮), GetIOBitIndex((int)DIName.暂停按钮), out sts);
  3293. if (!sts)
  3294. {
  3295. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.启动 ), GetIOBitIndex((int)DOName.启动), true);
  3296. Task.Run(async () =>
  3297. {
  3298. await Task.Delay(500);
  3299. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.启动), GetIOBitIndex((int)DOName.启动), false);
  3300. });
  3301. }
  3302. }
  3303. pStopWatch.Start();
  3304. pRunSpeedWatch.Start();
  3305. Log("启动", $"暂停 -> 继续");
  3306. LedRun();
  3307. _isRuning = true;
  3308. statusMgr.GotoAuto();
  3309. SendStatus();
  3310. ret = true;
  3311. return ret;
  3312. }
  3313. #endregion
  3314. #region 文件删除
  3315. public void DelectPictureFile()
  3316. {
  3317. //删除文件
  3318. Task.Factory.StartNew(() =>
  3319. {
  3320. //图片
  3321. if (confMgr.SysConfigParams.DefectSrcImag.AutoDelete)
  3322. statusMgr.DeleteFiles(confMgr.SysConfigParams.DefectSrcImag.SavePath, confMgr.SysConfigParams.DefectSrcImag.AutoDeleteDays, true);
  3323. if (confMgr.SysConfigParams.DefectSmallImag.AutoDelete)
  3324. statusMgr.DeleteFiles(confMgr.SysConfigParams.DefectSmallImag.SavePath, confMgr.SysConfigParams.DefectSmallImag.AutoDeleteDays, true);
  3325. if (confMgr.SysConfigParams.DefectSplicImag.AutoDelete)
  3326. statusMgr.DeleteFiles(confMgr.SysConfigParams.DefectSplicImag.SavePath, confMgr.SysConfigParams.DefectSplicImag.AutoDeleteDays, true);
  3327. if (confMgr.SysConfigParams.CamImag.AutoDelete)
  3328. statusMgr.DeleteFiles(confMgr.SysConfigParams.CamImag.SavePath, confMgr.SysConfigParams.CamImag.AutoDeleteDays, true);
  3329. //日志
  3330. if (confMgr.SysConfigParams.AutoDeleteLog)
  3331. statusMgr.DeleteFiles(confMgr.SysConfigParams.LogPath, confMgr.SysConfigParams.AutoDeleteLogData, true);
  3332. });
  3333. }
  3334. #region 数据保存
  3335. private async void saveCurrRecord(int key)
  3336. {
  3337. Records model = null;
  3338. int step = 0;
  3339. try
  3340. {
  3341. _isDefect = true;
  3342. Log( "入库", $"准备入库key={key}");
  3343. //foreach (int itemKey in htTask.Keys)
  3344. // AddTextEvent(DateTime.Now,"入库", $"htTask {itemKey}");
  3345. step = 1;
  3346. model = Hashtable.Synchronized(htTask)[key] as Records;
  3347. //model = htTask[key] as Records;
  3348. step = 2;
  3349. if (model.Len == 0)
  3350. {
  3351. Log("入库完成", $"小于1米不记录");
  3352. _isDefect = false;
  3353. return;
  3354. }
  3355. //model.BatchId = batchId;
  3356. //model.ReelId = reelId;
  3357. //model.ErpLen = erpLen;
  3358. while (model.ScannerPhotoCount > model.ScannerPhotoFinishCount)
  3359. await Task.Delay(100);
  3360. step = 3;
  3361. //计算等级标准
  3362. List<GradeLimit> gradeLimitList = model.ProductInfo.GradeLimitList;
  3363. if (gradeLimitList != null && gradeLimitList.Count > 0)
  3364. {
  3365. step = 4;
  3366. int count;
  3367. foreach (GradeLimit item in gradeLimitList)
  3368. {
  3369. if (model.DefectInfoList != null && model.DefectInfoList.Count > 0)
  3370. {
  3371. count = model.DefectInfoList.Where(m => m.Code == item.Code).Count();
  3372. if (count <= item.A && model.Grade <= 1) model.Grade = 1;
  3373. else if (count <= item.B && item.B > 0 && model.Grade <= 2) model.Grade = 2;
  3374. else if (count <= item.C && item.C > 0 && model.Grade <= 3) model.Grade = 3;
  3375. else if (count <= item.D && item.D > 0 && model.Grade <= 4) model.Grade = 4;
  3376. else if (count <= item.E && item.E > 0 && model.Grade <= 5) model.Grade = 5;
  3377. else if (count > 0) model.Grade = 6;//不合格
  3378. Log("标准判断", $"({key}) 条码({model.BarCode}),标准={(char)(model.Grade + 64)} [{item.Code}:{count};A<={item.A};B<={item.B};C<={item.C};D<={item.D};E<={item.E}]");
  3379. }
  3380. else
  3381. {
  3382. model.Grade = 1;
  3383. Log("标准判断", $"({key}) 条码({model.BarCode}),标准={(char)(model.Grade + 64)} [{item.Code}:{0};A<={item.A};B<={item.B};C<={item.C};D<={item.D};E<={item.E}]");
  3384. }
  3385. }
  3386. step = 5;
  3387. }
  3388. model.Qualified = (model.Grade < 6);//是否合格
  3389. if (!RecordService.InsertNav(model))
  3390. throw new Exception("写库失败!");
  3391. Log("入库完成", $"({key}) 条码({model.BarCode})已完成检测-{model.ScannerPhotoCount}-{model.ScannerPhotoFinishCount}。");
  3392. htTask.Remove(key);
  3393. _isDefect = false;
  3394. }
  3395. catch (Exception ex)
  3396. {
  3397. _isDefect = false;
  3398. if (model == null)
  3399. Log("入库失败", $"记录({key})不存在{step}!" + ex.Message, WarningEnum.High);
  3400. else
  3401. Log("入库失败", $"({key}) 条码({model.BarCode})检测完成,但保存检测记录失败{step}:" + ex.Message, WarningEnum.High);
  3402. }
  3403. }
  3404. #endregion
  3405. #endregion
  3406. #region 表格事件查询
  3407. public DefectInfo GetDefectInfo(long uid)
  3408. {
  3409. if (currKey == 0)
  3410. return null;
  3411. Records record = Hashtable.Synchronized(htTask)[currKey] as Records;
  3412. //var defectInfo = record.DefectInfoList[record.DefectInfoList.Count - e.RowIndex-1];//按顺序索引引用
  3413. var defectInfo = record.DefectInfoList.FirstOrDefault(m => m.uid == uid);
  3414. return defectInfo;
  3415. }
  3416. #endregion
  3417. #region 拷贝产品
  3418. /// <summary>
  3419. /// 拷贝产品
  3420. /// </summary>
  3421. /// <param name="list"></param>
  3422. /// <param name="liIndex"></param>
  3423. /// <param name="stepID">流程ID</param>
  3424. /// <param name="stepInfo">流程</param>
  3425. /// <returns></returns>
  3426. public bool ProductCopy(List<Product> list, int liIndex)
  3427. {
  3428. Product newProduct = new Product()
  3429. {
  3430. Code = list[liIndex].Code + "_clone",
  3431. Name = $"{list[liIndex].Name} (克隆)",
  3432. Spec = list[liIndex].Spec,
  3433. Material = list[liIndex].Material,
  3434. Color = list[liIndex].Color,
  3435. ColorName = list[liIndex].ColorName,
  3436. ColorValue = list[liIndex].ColorValue,
  3437. LightValue = list[liIndex].LightValue,
  3438. ExposureTime = list[liIndex].ExposureTime,
  3439. Gain = list[liIndex].Gain,
  3440. TensionValue = list[liIndex].TensionValue,
  3441. Note = list[liIndex].Note,
  3442. ModelName = list[liIndex].ModelName,
  3443. DefectAreaLimit = list[liIndex].DefectAreaLimit,
  3444. DefectCountLimit = list[liIndex].DefectCountLimit,
  3445. DefectPauseForUser = list[liIndex].DefectPauseForUser,
  3446. DefectCntLength = list[liIndex].DefectCntLength,
  3447. WarnDefect = list[liIndex].WarnDefect,
  3448. OpenThicknessDetection = list[liIndex].OpenThicknessDetection,
  3449. ThicknessDetectionStopDis = list[liIndex].ThicknessDetectionStopDis,
  3450. residueWarnningLen = list[liIndex].residueWarnningLen,
  3451. QualifiedLimitList = new List<QualifiedLimit>(),
  3452. GradeLimitList = new List<GradeLimit>(),
  3453. DefectPauseOption = list[liIndex].DefectPauseOption,
  3454. //OrderList = new List<Order>(),
  3455. ModifyUserCode = userMgr.LoginUser.Code,
  3456. CreateUserCode = userMgr.LoginUser.Code
  3457. };
  3458. foreach (var item in list[liIndex].QualifiedLimitList)
  3459. {
  3460. newProduct.QualifiedLimitList.Add(new QualifiedLimit()
  3461. {
  3462. Code = item.Code,
  3463. ZXD = item.ZXD,
  3464. Pid = item.Pid,
  3465. Name = item.Name,
  3466. Area = item.Area,
  3467. ContrastTop = item.ContrastTop,
  3468. ContrastLower = item.ContrastLower,
  3469. IsOR = item.IsOR,
  3470. NameCode = item.NameCode,
  3471. DefectWarnLength = item.DefectWarnLength,
  3472. DefectWarnCnt = item.DefectWarnCnt,
  3473. ModifyUserCode = userMgr.LoginUser.Code,
  3474. CreateUserCode = userMgr.LoginUser.Code
  3475. });
  3476. }
  3477. foreach (var item in list[liIndex].GradeLimitList)
  3478. {
  3479. newProduct.GradeLimitList.Add(new GradeLimit()
  3480. {
  3481. Pid = item.Pid,
  3482. Code = item.Code,
  3483. A = item.A,
  3484. B = item.B,
  3485. C = item.C,
  3486. D = item.D,
  3487. E = item.E,
  3488. ModifyUserCode = userMgr.LoginUser.Code,
  3489. CreateUserCode = userMgr.LoginUser.Code
  3490. });
  3491. }
  3492. bool result = PdtService.InsertNav(newProduct);
  3493. return result;
  3494. }
  3495. #endregion
  3496. #region 加载二次判定项
  3497. /// <summary>
  3498. /// 二次项判断名称列表
  3499. /// </summary>
  3500. private List<string> DefectItemsPuaseNameList = new List<string>();
  3501. public void LoadDefectItemsPuase(List<string> list)
  3502. {
  3503. DefectItemsPuaseNameList.Clear();
  3504. foreach (var item in list)
  3505. {
  3506. DefectItemsPuaseNameList.Add(item);
  3507. }
  3508. }
  3509. #endregion
  3510. #region 二次判断完成修改
  3511. public Product GetProduct(string name)
  3512. {
  3513. return PdtService.GetModelNavByName(name);
  3514. }
  3515. /// <summary>
  3516. /// 删除忽略项
  3517. /// </summary>
  3518. /// <param name="curRecord"></param>
  3519. /// <param name="lstDel"></param>
  3520. public void DelDefectEdit(Records curRecord, List<DefectInfo> lstDel)
  3521. {
  3522. foreach (var item in lstDel)
  3523. {
  3524. curRecord.DefectInfoList.Remove(item);
  3525. }
  3526. }
  3527. #endregion
  3528. #region 加载打标判定项
  3529. /// <summary>
  3530. /// 打标项判断名称列表
  3531. /// </summary>
  3532. private List<string> DefectItemsDBNameList = new List<string>();
  3533. public void LoadDefectItemsDB(List<string> list)
  3534. {
  3535. DefectItemsDBNameList.Clear();
  3536. foreach (var item in list)
  3537. {
  3538. DefectItemsDBNameList.Add(item);
  3539. }
  3540. }
  3541. #endregion
  3542. #region 启动打标
  3543. public void StartDB()
  3544. {
  3545. if (confMgr.SysConfigParams.OpenIO)
  3546. {
  3547. bool sts;
  3548. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.打标), GetIOBitIndex((int)DOName.打标), true);
  3549. Task.Run(async () =>
  3550. {
  3551. await Task.Delay(200);
  3552. ioCardDev.WriteBitState(GetIOPortIndex((int)DOName.打标), GetIOBitIndex((int)DOName.打标), false);
  3553. });
  3554. }
  3555. }
  3556. #endregion
  3557. }
  3558. #region 系统事件
  3559. /// <summary>
  3560. /// 流程事件
  3561. /// </summary>
  3562. public class RunEventArgs : EventArgs
  3563. {
  3564. private int _cmd;
  3565. public int Cmd { get { return _cmd; } }
  3566. private int _picIndex;
  3567. public int PicIndex { get { return _picIndex; } }
  3568. private Mat _pic;
  3569. public Mat Pic { get { return _pic; } }
  3570. public RunEventArgs(int index, Mat pic)
  3571. {
  3572. this._cmd = 6;
  3573. this._picIndex = index;
  3574. this._pic = pic.Clone();
  3575. }
  3576. private bool _over;
  3577. public bool Over { get { return _over; } }
  3578. public RunEventArgs(bool ov)
  3579. {
  3580. this._cmd = 10;
  3581. this._over = ov;
  3582. }
  3583. private List<object[]> _dataRowlist = new List<object[]>();
  3584. public List<object[]> DataRowlist { get { return _dataRowlist; } }
  3585. public RunEventArgs(List<object[]> dataRowlist)
  3586. {
  3587. this._cmd = 11;
  3588. this._dataRowlist = dataRowlist;
  3589. }
  3590. private Image _defectimg;
  3591. public Image Defectimg { get { return _defectimg; } }
  3592. public RunEventArgs(Image defectimg)
  3593. {
  3594. this._cmd = 12;
  3595. this._defectimg = defectimg;
  3596. }
  3597. private List<float[]> _points;
  3598. public List<float[]> Points { get { return _points; } }
  3599. public RunEventArgs(List<float[]> pints)
  3600. {
  3601. this._cmd = 13;
  3602. this._points = pints;
  3603. }
  3604. private double _len;
  3605. public double Len { get { return _len; } }
  3606. private double _speed;
  3607. public double Speed { get { return _speed; } }
  3608. public RunEventArgs(double len, double spd)
  3609. {
  3610. this._cmd = 14;
  3611. this._len = len;
  3612. this._speed = spd;
  3613. }
  3614. private Mat _Matimg;
  3615. public Mat DefectMat { get { return _Matimg; } }
  3616. public RunEventArgs(Mat defectimg)
  3617. {
  3618. this._cmd = 15;
  3619. this._Matimg = defectimg.Clone();
  3620. //this._Matimg = defectimg;
  3621. }
  3622. private int _cam1ImgCnt;
  3623. public int Cam1ImgCnt { get { return _cam1ImgCnt; } }
  3624. private int _cam2ImgCnt;
  3625. public int Cam2ImgCnt { get { return _cam2ImgCnt; } }
  3626. private int _defectImgCnt;
  3627. public int DeefectImgCnt { get { return _defectImgCnt; } }
  3628. private int _saveImgCnt;
  3629. public int SaveImgCnt { get { return _saveImgCnt; } }
  3630. private string _definfoCnt;
  3631. public string _DefinfoCnt { get { return _definfoCnt; } }
  3632. public RunEventArgs(int cnt1, int cnt2, string definfo)
  3633. {
  3634. this._cmd = 16;
  3635. this._cam1ImgCnt = cnt1;
  3636. this._cam2ImgCnt = cnt2;
  3637. this._definfoCnt = definfo;
  3638. }
  3639. public RunEventArgs(int cnt1, int cnt2, int cnt3)
  3640. {
  3641. this._cmd = 20;
  3642. //this._cam1ImgCnt = cnt1;
  3643. //this._cam2ImgCnt = cnt2;
  3644. this._saveImgCnt = cnt3;
  3645. }
  3646. private int _lightValue;
  3647. public int LightValue { get { return _lightValue; } }
  3648. public RunEventArgs(int val)
  3649. {
  3650. this._cmd = 17;
  3651. this._lightValue = val;
  3652. }
  3653. private Product _md;
  3654. public Product MD { get { return _md; } }
  3655. public RunEventArgs(Product md)
  3656. {
  3657. this._cmd = 18;
  3658. this._md = md;
  3659. }
  3660. private int _imgIndex;
  3661. public int ImgIndex { get { return _imgIndex; } }
  3662. private List<DefectInfo> _lstEditDefect;
  3663. public List<DefectInfo> LstEditDefect { get { return _lstEditDefect; } }
  3664. private List<DefectInfo> _lstEditInfo;
  3665. public List<DefectInfo> LstEditInfo { get { return _lstEditInfo; } }
  3666. private Records _records;
  3667. public Records Records { get { return _records; } }
  3668. private Mat _tagImg;
  3669. public Mat TagImg { get { return _tagImg; } }
  3670. public RunEventArgs(int index, List<DefectInfo> lstEditDefect, Records currRecord, Mat img, List<DefectInfo> lstEditInfo)
  3671. {
  3672. this._cmd = 19;
  3673. this._imgIndex = index;
  3674. this._lstEditDefect = lstEditDefect;
  3675. this._records = currRecord;
  3676. this._tagImg = img;
  3677. this._lstEditInfo = lstEditInfo;
  3678. }
  3679. public RunEventArgs(int index, List<DefectInfo> lstEditDefect, Records currRecord, Mat img)
  3680. {
  3681. this._cmd = 21;
  3682. this._imgIndex = index;
  3683. this._lstEditDefect = lstEditDefect;
  3684. this._records = currRecord;
  3685. this._tagImg = img;
  3686. }
  3687. }
  3688. /// <summary>
  3689. /// 主窗体事件
  3690. /// </summary>
  3691. public class MainEventArgs : EventArgs
  3692. {
  3693. private string _tag;
  3694. public string Tag { get { return _tag; } }
  3695. private string _message;
  3696. public string Message { get { return _message; } }
  3697. private int _showIndex;
  3698. public int ShowIndex { get { return _showIndex; } }
  3699. private WarningEnum _warning;
  3700. public WarningEnum Warning { get { return _warning; } }
  3701. private bool _show;
  3702. public bool show { get { return _show; } }
  3703. public MainEventArgs(int index)
  3704. {
  3705. this._showIndex = index;
  3706. this._show = true;
  3707. }
  3708. public MainEventArgs(int index, string message)
  3709. {
  3710. this._message = message;
  3711. this._showIndex = index;
  3712. this._show = true;
  3713. }
  3714. public MainEventArgs(string tag, string message, WarningEnum warning = WarningEnum.Normal)
  3715. {
  3716. this._tag = tag;
  3717. this._message = message;
  3718. this._showIndex = 0;
  3719. this._warning = warning;
  3720. this._show = true;
  3721. }
  3722. public MainEventArgs(string tag, string message, WarningEnum warning = WarningEnum.Normal, bool Show = true)
  3723. {
  3724. this._tag = tag;
  3725. this._message = message;
  3726. this._showIndex = 0;
  3727. this._warning = warning;
  3728. this._show = Show;
  3729. }
  3730. }
  3731. /// <summary>
  3732. /// 初始化事件
  3733. /// </summary>
  3734. public class InitEventArgs : EventArgs
  3735. {
  3736. private string _message;
  3737. public string Message { get { return _message; } }
  3738. private bool _isInitialized;
  3739. public bool IsInitialized { get { return _isInitialized; } }
  3740. public InitEventArgs()
  3741. {
  3742. }
  3743. public InitEventArgs(string message, bool isInitialized = false)
  3744. {
  3745. this._message = message;
  3746. this._isInitialized = isInitialized;
  3747. }
  3748. }
  3749. #endregion
  3750. }