革博士V2程序
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

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