AutoAnalysisDialog.cs 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327
  1. using AiControlRequest;
  2. using OpenCvSharp;
  3. using OpenCvSharp.Extensions;
  4. using PaintDotNet;
  5. using PaintDotNet.Base.CommTool;
  6. using PaintDotNet.DbOpreate.DbBll;
  7. using PaintDotNet.DbOpreate.DbModel;
  8. using PaintDotNet.ImageCollect;
  9. using StageController;
  10. using System;
  11. using System.Collections.Generic;
  12. using System.ComponentModel;
  13. using System.Data;
  14. using System.Drawing;
  15. using System.Drawing.Imaging;
  16. using System.IO;
  17. using System.Linq;
  18. using System.Reflection;
  19. using System.Text;
  20. using System.Threading;
  21. using System.Threading.Tasks;
  22. using System.Windows.Forms;
  23. using TUCamera;
  24. using static AiControlRequest.AiControl;
  25. namespace Metis.AutoAnalysis
  26. {
  27. internal partial class AutoAnalysisDialog : FloatingToolForm, IStageEvent
  28. {
  29. /// <summary>
  30. /// 样品台展示控件
  31. /// </summary>
  32. SampleStageControl _samplesControl;
  33. Dictionary<string, SampleStageModel> _stageSettingList;
  34. SampleStageModel _stageSettingNow;
  35. string _stageSettingName;
  36. /// <summary>
  37. /// 结果展示控件
  38. /// </summary>
  39. ScanGridControl _scanGird;
  40. AxisController m_stage;
  41. private double m_PxLength;
  42. Dictionary<int, string> ResultList = new Dictionary<int, string>();
  43. protected int ConvertUMToPX(double length)
  44. {
  45. return (int)(length / m_PxLength);
  46. }
  47. protected double ConvertPXToUm(double length)
  48. {
  49. return length * m_PxLength;
  50. }
  51. public int VisionWidthPixel;
  52. public int VisionHeightPixel;
  53. public double VisionWidth;
  54. public double VisionHeight;
  55. public int NumRow;
  56. public int NumCol;
  57. private AppWorkspace _app;
  58. public AutoAnalysisDialog(AppWorkspace app)
  59. {
  60. _app = app;
  61. InitializeComponent();
  62. Startup.instance.rules.TryGetValue(MeasurementUnit.Micron, out m_PxLength);
  63. _scanGird = new ScanGridControl();
  64. _scanGird.MouseDown += _scanGird_MouseDown;
  65. pnlScanGrid.Controls.Add(_scanGird);
  66. InitSmapleStageControl();
  67. DirRoot = @"D:\AiTest";//Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
  68. _camera = TUCameraManager.GetInstance().GetCurrentCamera();
  69. var size = _camera.GetResolution();
  70. VisionWidthPixel = size.Width == 0 ? 1000 : size.Width;
  71. VisionHeightPixel = size.Height == 0 ? 1000 : size.Height;
  72. VisionWidth = ConvertPXToUm(VisionWidthPixel);
  73. VisionHeight = ConvertPXToUm(VisionHeightPixel);
  74. lblImageSize.Text = string.Format("{0:f0}*{1:f0}", VisionWidthPixel, VisionHeightPixel);
  75. SetAnalyzeModelFromXml("自动分析");
  76. }
  77. #region Load Close
  78. private void AutoAnalysisDialog_Load(object sender, EventArgs e)
  79. {
  80. CameraConfigs.GetInstance().CameraParamInit();
  81. _stageSettingList = SampleStageManager.GetAll();
  82. foreach (var s in _stageSettingList.Keys) cmbSampleStageList.Items.Add(s);
  83. if (cmbSampleStageList.Items.Count > 0)
  84. cmbSampleStageList.SelectedIndex = 0;
  85. cmbScanMode.SelectedIndex = 0;
  86. cmbAutoFocusParm.SelectedIndex = 0;
  87. tmrUpdateUI.Start();
  88. tmrUpdateUI.Tick += TmrUpdateUI_Tick;
  89. UpdateUserList();
  90. StartCapture();
  91. InitStage();
  92. InitOfflineTest();
  93. InitCheckConfig();
  94. }
  95. int[] _detectParams = new int[3];
  96. private CheckConfigModel _checkconfig;
  97. private void CheckItemChange(string str)
  98. {
  99. for (int i = 0; i < 3; i++)
  100. _detectParams[i] = int.Parse(str.Split(',')[i]);
  101. }
  102. private void InitCheckConfig()
  103. {
  104. try
  105. {
  106. string CheckconfigPath = @"Automation\checkitem\checkconfig.xml";
  107. _checkconfig = XmlSerializeHelper.Load<CheckConfigModel>(CheckconfigPath);
  108. cmbProjuctSelect.DropDownStyle = ComboBoxStyle.DropDownList;
  109. foreach (var item in _checkconfig.Items)
  110. {
  111. cmbProjuctSelect.Items.Add(item.Name);
  112. cmbProjuctSelect.SelectedIndex = 0;
  113. }
  114. }
  115. catch
  116. {
  117. MessageBox.Show("请检查\"\\Automation\\checkitem\\checkconfig.xml\"文件是否有错误。", "检测配置文件错误");
  118. }
  119. }
  120. /// <summary>
  121. /// 更新控件状态
  122. /// </summary>
  123. private void TmrUpdateUI_Tick(object sender, EventArgs e)
  124. {
  125. grpStage.Enabled = !_isWorking;
  126. grpFocus.Enabled = !_isWorking;
  127. grpStageInfo.Enabled = !_isWorking;
  128. grpStageDisplay.Enabled = !_isWorking;
  129. grpWorkOperate.Enabled = m_stage.IsOpen;
  130. grpAiOperate.Enabled = !_isWorking || _pause;
  131. grpRange.Enabled = !_isWorking;
  132. btnLocate.Enabled = !_isWorking & m_stage.IsOpen;
  133. btnLookBack.Enabled = _workDone || _pause;
  134. btnAnalysis.Enabled = _workDone || _pause;
  135. btnReport.Enabled = _workDone;
  136. btnStart.Text = !_isWorking || _pause ? "开始" : "暂停";
  137. btnStop.Enabled = _isWorking;
  138. cmbProjuctSelect.Enabled = !_isWorking;
  139. if (_isWorking)
  140. {
  141. _resultScanSelect = -1;
  142. }
  143. }
  144. private void AutoAnalysisDialog_FormClosing(object sender, FormClosingEventArgs e)
  145. {
  146. StopCapture();
  147. StopWork();
  148. }
  149. public void InitStage()
  150. {
  151. m_stage = AxisController.GetInstance();
  152. pnlTest.Width = 0;
  153. if (!m_stage.IsOpen)
  154. {
  155. // MessageBox.Show(PdnResources.GetString("Message.AxisController.NotConnected"));
  156. //grpWorkOperate.Enabled = false;
  157. return;
  158. }
  159. m_stage.SetWorkspeedXY();
  160. var dialog = TransferProgressDialog.CreatDialog("平台复位", "复位中...", null, "Stop");
  161. m_stage.ResetStage(
  162. () =>
  163. {
  164. this.Invoke(new Action(dialog.Close));
  165. });
  166. dialog.ShowDialog();
  167. }
  168. #endregion
  169. private void cmbSampleStageList_SelectedIndexChanged(object sender, EventArgs e)
  170. {
  171. _stageSettingNow = _stageSettingList[cmbSampleStageList.Text];
  172. _stageSettingName = cmbSampleStageList.Text;
  173. UpdateSmapleStageControl();
  174. BuildTableList();
  175. var hc = Math.Ceiling(_stageSettingNow.Width * 1000 / VisionWidth);
  176. var vc = Math.Ceiling(_stageSettingNow.Height * 1000 / VisionHeight);
  177. nupHorizon.Value = (decimal)hc;
  178. nupVertical.Value = (decimal)vc;
  179. ClearResult();
  180. }
  181. #region ScanGrid Display
  182. private void nupHorizon_ValueChanged(object sender, EventArgs e)
  183. {
  184. var colN = (int)nupHorizon.Value;
  185. var rowN = (int)nupVertical.Value;
  186. if (colN != 0 && rowN != 0)
  187. UpdateScanGrid(colN, rowN);
  188. else { return; }
  189. var width = ConvertUMToPX(_stageSettingNow.Width * 1000 / colN);
  190. var height = ConvertUMToPX(_stageSettingNow.Height * 1000 / rowN);
  191. lblStageSize.Text = string.Format("{0:f0}*{1:f0}", width, height);
  192. }
  193. private void UpdateScanGrid(int c, int r)
  194. {
  195. lblTotal.Text = (c * r).ToString();
  196. NumCol = c;
  197. NumRow = r;
  198. _scanGird.NumCol = c;
  199. _scanGird.NumRow = r;
  200. _scanGird.VsnWitch = VisionWidth;
  201. _scanGird.VsnHeight = VisionHeight;
  202. _scanGird.InitGrid(_stageSettingNow);
  203. }
  204. private void _scanGird_MouseDown(object sender, MouseEventArgs e)
  205. {
  206. _resultLookId = _scanGird.GetHitId(e.X, e.Y);
  207. _resultScanSelect = _scanGird.GetIndex(e.X, e.Y);
  208. ShowResult();
  209. }
  210. #endregion
  211. #region SampleStage
  212. void InitSmapleStageControl()
  213. {
  214. _samplesControl = new SampleStageControl();
  215. _samplesControl.OnSelectChanged += (value) =>
  216. {
  217. UpdateInfoTable(value);
  218. // if (_workDone)
  219. UpdateScanGridByResult(value);
  220. };
  221. pnlStageDisplay.Controls.Add(_samplesControl);
  222. }
  223. private void UpdateSmapleStageControl()
  224. {
  225. _samplesControl.Update(_stageSettingNow);
  226. }
  227. private void ResetSmapleState()
  228. {
  229. for (int i = 0; i < _tables.Length; i++)
  230. {
  231. var table = _tables[i];
  232. if (table == null)
  233. _samplesControl.SetState(i, 0);
  234. else
  235. _samplesControl.SetState(i, 1);
  236. }
  237. }
  238. #endregion
  239. #region User
  240. List<string> _userList;
  241. private void UpdateUserList()
  242. {
  243. cmbUser.Items.Clear();
  244. _userList = SampleStageManager.GetUsers();
  245. foreach (var s in _userList) cmbUser.Items.Add(s);
  246. if (cmbUser.Items.Count > 0)
  247. cmbUser.SelectedIndex = 0;
  248. }
  249. private void btnAddUser_Click(object sender, EventArgs e)
  250. {
  251. var form = new AddUser() { CallOK = AddUser };
  252. form.TopMost = true;
  253. form.ShowDialog();
  254. }
  255. private void AddUser(string s)
  256. {
  257. if (_userList.Contains(s))
  258. return;
  259. _userList.Insert(0, s);
  260. SampleStageManager.SaveUsers(_userList);
  261. UpdateUserList();
  262. }
  263. private void DelUser(string s)
  264. {
  265. _userList.Remove(s);
  266. SampleStageManager.SaveUsers(_userList);
  267. UpdateUserList();
  268. }
  269. private void btnDelUser_Click(object sender, EventArgs e)
  270. {
  271. DelUser(cmbUser.Text);
  272. }
  273. #endregion
  274. #region Information
  275. string[] _infos;
  276. DataTable[] _tables;
  277. char _spliter = ';';
  278. string GetUser()
  279. {
  280. return cmbUser.Text;
  281. }
  282. void BuildTableList()
  283. {
  284. dgvStageInfo.DataSource = null;
  285. _tables = new DataTable[_stageSettingNow.WorkPoits.Count];
  286. _infos = new string[_stageSettingNow.WorkPoits.Count];
  287. }
  288. private void txbInfo_KeyDown(object sender, KeyEventArgs e)
  289. {
  290. if (e.KeyCode == Keys.Enter)
  291. {
  292. btnAddInfo_Click(null, null);
  293. }
  294. }
  295. private void btnAddInfo_Click(object sender, EventArgs e)
  296. {
  297. if (!_tables.Any((t) => t == null))
  298. {
  299. MessageBox.Show("所有工位已经添加完成");
  300. return;
  301. }
  302. var user = GetUser();
  303. if (string.IsNullOrEmpty(user))
  304. {
  305. MessageBox.Show("请先添加检测员。");
  306. return;
  307. }
  308. var infostr = txbInfo.Text;
  309. if (string.IsNullOrEmpty(infostr)) return;
  310. txbInfo.Text = "";
  311. var list = infostr.Split(_spliter);
  312. var sampleEditSelect = _tables.ToList().FindIndex((t) => t == null);
  313. _samplesControl.SelectIndex = sampleEditSelect;
  314. var table = new DataTable();
  315. table.Columns.Add("工位 ", typeof(string));
  316. table.Columns.Add("样品信息 ", typeof(string));
  317. table.Columns.Add("检测 ", typeof(bool));
  318. table.Columns.Add("结果 ", typeof(string));
  319. table.Columns.Add("检测员 ", typeof(string));
  320. for (int i = 0; i < list.Length; i++)
  321. {
  322. var row = table.NewRow();
  323. if (i == 0)
  324. row[0] = "#" + (sampleEditSelect + 1);
  325. int j = 1;
  326. row[j++] = list[i];
  327. row[j++] = true;
  328. row[j++] = "";
  329. row[j++] = user;
  330. table.Rows.Add(row);
  331. }
  332. _tables[sampleEditSelect] = table;
  333. _infos[sampleEditSelect] = infostr;
  334. _samplesControl.SetState(sampleEditSelect, 1);
  335. UpdateInfoTable(sampleEditSelect);
  336. }
  337. private void UpdateInfoTable(int i)
  338. {
  339. var table = _tables[i];
  340. dgvStageInfo.DataSource = table;
  341. }
  342. private void btnDelInfo_Click(object sender, EventArgs e)
  343. {
  344. if (_samplesControl.SelectIndex < 0) return;
  345. var i = _samplesControl.SelectIndex;
  346. _tables[i] = null;
  347. _infos[i] = null;
  348. dgvStageInfo.DataSource = null;
  349. _samplesControl.SetState(i, 0);
  350. }
  351. private bool IsCheck(int id)
  352. {
  353. return (bool)dgvStageInfo.Rows[id].Cells[2].Value;
  354. }
  355. #endregion
  356. #region Work
  357. int _workSampleIndex;
  358. int _workScanIndex;
  359. bool _isWorking;
  360. bool _pause = false;
  361. bool _workDone;
  362. bool _isOnce = false;
  363. bool _restart = false;
  364. ResultModel _resultWorking;
  365. /// <summary>
  366. /// 聚焦间隔
  367. /// </summary>
  368. int _focusInterval = 1;
  369. /// <summary>
  370. /// 蛇形扫描: 0:连续,1:间隔
  371. /// </summary>
  372. int _mode = 0;
  373. private void btnStart_Click(object sender, EventArgs e)
  374. {
  375. if (string.IsNullOrEmpty(_dirRoot))
  376. {
  377. MessageBox.Show("请选择");
  378. return;
  379. }
  380. var str = cmbProjuctSelect.Text;
  381. if (string.IsNullOrEmpty(str))
  382. {
  383. MessageBox.Show("检测项目不能为空");
  384. return;
  385. }
  386. var item = _checkconfig.Items.First((i) => i.Name == str);
  387. CheckItemChange(item.Value);
  388. var table = _tables[0];
  389. if (table == null)
  390. {
  391. MessageBox.Show("请添加样品信息。");
  392. return;
  393. }
  394. var hasCheck = false;
  395. for (int i = 0; i < table.Rows.Count; i++)
  396. {
  397. hasCheck |= (bool)table.Rows[i][2];
  398. }
  399. if (!hasCheck)
  400. {
  401. MessageBox.Show("请选择检测项。");
  402. return;
  403. }
  404. if (!_isWorking)
  405. {
  406. StartWork();
  407. }
  408. else
  409. {
  410. if (_pause)
  411. {
  412. _restart = rdbReplayAll.Checked;
  413. _isWorking = !_restart;
  414. }
  415. else
  416. {
  417. }
  418. _pause = !_pause;
  419. }
  420. _isOnce = rdbOnlyCurrent.Checked;
  421. }
  422. private void btnStop_Click(object sender, EventArgs e)
  423. {
  424. StopWork();
  425. }
  426. private void StartWork()
  427. {
  428. _workSampleIndex = 0;
  429. _workScanIndex = 0;
  430. _resultCmpAll = new List<string>();
  431. _resultList = new List<ResultModel>();
  432. NewWorkDir();
  433. InitAi(_dirCurrent);
  434. Directory.Delete(_dirCurrent);
  435. _isWorking = true;
  436. ResetSmapleState();
  437. new Thread(Runtime).Start();
  438. }
  439. private void PauseWork()
  440. {
  441. _pause = true;
  442. }
  443. private void StopWork()
  444. {
  445. AutoFocusWorkflow.Stop();
  446. _pause = false;
  447. _isWorking = false;
  448. }
  449. private void Runtime()
  450. {
  451. Console.WriteLine("In to work runtime");
  452. while (_isWorking)
  453. {
  454. while (_pause)
  455. {
  456. Thread.Sleep(50);
  457. if (!_isWorking) break;
  458. }
  459. ToWorkStartPoint(_workSampleIndex);
  460. NewWorkDir();
  461. aicontrol.GradePaht = _dirCurrent;
  462. var rule = Startup.instance.ruleDB;
  463. if (rule != null)
  464. {
  465. int mul = (int)rule.gain_multiple;
  466. double umperpx = (double)(rule.physical_length / (decimal)rule.pixel_length);
  467. // aicontrol.StartAndSetGradeParam(catagoryParam.Inclusion, itemParam.Inclusion, jsonParam.InclusionALL, mul, umperpx);
  468. aicontrol.StartAndSetGradeParam((catagoryParam)_detectParams[0], (itemParam)_detectParams[1], (jsonParam)_detectParams[2], mul, umperpx);
  469. }
  470. else
  471. {
  472. aicontrol.StartAndSetGradeParam((catagoryParam)_detectParams[0], (itemParam)_detectParams[1], (jsonParam)_detectParams[2], 1, 1);
  473. }
  474. _samplesControl.SetState(_workSampleIndex, 2);
  475. _scanGird.Reset();
  476. //Scan
  477. ScanSampleWorkflow();
  478. if (!_isWorking) break;
  479. _samplesControl.SetState(_workSampleIndex, 3);
  480. _resultFlag = _workSampleIndex + 1;
  481. EndGrade(_workSampleIndex);
  482. if (_workSampleIndex < _stageSettingNow.WorkPoits.Count - 1)
  483. ToWorkStartPoint(_workSampleIndex + 1);
  484. WaitAiCompleteAll();
  485. _workSampleIndex++;
  486. if (_workSampleIndex >= _stageSettingNow.WorkPoits.Count) break;
  487. }
  488. Console.WriteLine("Out of work runtime.");
  489. //当全部扫码完成退出循环,_isWorking依然为true,则认为完成
  490. _workDone = _isWorking;
  491. StopWork();
  492. if (_restart)
  493. {
  494. _restart = false;
  495. StartWork();
  496. }
  497. }
  498. private void ScanSampleWorkflow()
  499. {
  500. for (; _workScanIndex < NumCol * NumRow && _isWorking; _workScanIndex += 1 + _mode)
  501. {
  502. while (_pause)
  503. {
  504. Thread.Sleep(50);
  505. if (!_isWorking) return;
  506. }
  507. if (_isOnce) _pause = true;
  508. //Console.Write("Before To Next:");
  509. m_stage.WaitMoveDone();
  510. ToNext(Offx, Offy, _workScanIndex);
  511. _scanGird.SetDoning(_workScanIndex, _workScanIndex / (_mode + 1) + 1);
  512. _resultWorking = new ResultModel() { SampleId = _workSampleIndex, ScanId = _workScanIndex, ResultId = _workScanIndex / (_mode + 1) + 1 };
  513. _resultList.Add(_resultWorking);
  514. if (rbtAutoFocus.Checked)
  515. {
  516. if ((_workScanIndex / (_mode + 1) + 1) % _focusInterval == 0)
  517. AutoFocusWorkflow.AutoFocusFast(m_stage, () => _imgNow);
  518. }
  519. SetShoot();
  520. }
  521. _workScanIndex = 0;
  522. }
  523. bool _shootFlag = false;
  524. private void SetShoot()
  525. {
  526. _shootFlag = true;
  527. while (_isWorking && _shootFlag)
  528. { Thread.Sleep(10); }
  529. }
  530. private void CatchShoot(Bitmap img)
  531. {
  532. _shootFlag = false;
  533. _resultWorking.File = Save(img);
  534. var type = CheckPicBoundary(img);
  535. if (type == 3 || (type == 2 && _checkconfig.Border == 1))
  536. aicontrol.PostFileName(_resultWorking.FileName);
  537. }
  538. class ResultModel
  539. {
  540. public int SampleId;
  541. public int ScanId = -1;
  542. public bool Done;
  543. //public string Result;
  544. string _file;
  545. public string File
  546. {
  547. get => _file;
  548. set
  549. {
  550. _file = value;
  551. var i = value.LastIndexOf('\\');
  552. Dir = value.Substring(0, i + 1);
  553. FileName = value.Substring(i + 1);
  554. }
  555. }
  556. public string Dir;
  557. public string FileName;
  558. public int ResultId;
  559. }
  560. #endregion
  561. #region Move To
  562. float Offx => _stageSettingNow.Width * 1000 / NumCol;
  563. float Offy => _stageSettingNow.Height * 1000 / NumRow;
  564. /// <summary>
  565. /// 移动到开始位置
  566. /// </summary>
  567. /// <param name="i"></param>
  568. private void ToWorkStartPoint(int i)
  569. {
  570. var p = GetWorkStartPoint(i);
  571. m_stage.To(p.X, p.Y);
  572. }
  573. private PointF GetWorkStartPoint(int i)
  574. {
  575. var x = (_stageSettingNow.WorkPoits[i].X - _stageSettingNow.Width / 2) * 1000;
  576. var y = (_stageSettingNow.WorkPoits[i].Y - _stageSettingNow.Height / 2) * 1000;
  577. return new PointF(x, y);
  578. }
  579. private void ToNext(double offx, double offy, int i)
  580. {
  581. double x = 0, y = 0;
  582. int r = i / NumCol;
  583. int c = i % NumCol;
  584. if (_mode == 0)
  585. {
  586. if (i == 0) ;
  587. else if (c == 0)
  588. y = offy;
  589. else if (r % 2 == 0)
  590. x = offx;
  591. else
  592. x = -offx;
  593. }
  594. if (_mode == 1)
  595. {
  596. if (i == 0) ;
  597. else if (r % 2 == 0)
  598. {
  599. if (c == 0)
  600. {
  601. x = -offx;
  602. y = offy;
  603. }
  604. else if (c == 1)
  605. {
  606. x = offx;
  607. y = offy;
  608. }
  609. else x = 2 * offx;
  610. }
  611. else
  612. {
  613. if (c == 0)
  614. {
  615. x = offx;
  616. y = offy;
  617. }
  618. else if (c == 1)
  619. {
  620. x = -offx;
  621. y = offy;
  622. }
  623. else x = -2 * offx;
  624. }
  625. }
  626. m_stage.Move(x, y);
  627. // Console.Write("To Next:");
  628. m_stage.WaitMoveDone();
  629. }
  630. private void ToScanPoint(int sampleId, int scanId)
  631. {
  632. var p = GetWorkStartPoint(sampleId);
  633. float offx = scanId / NumCol % 2 == 0 ? scanId % NumCol : NumCol - scanId % NumCol - 1;
  634. float offy = (int)(scanId / NumCol);
  635. offx *= Offx;
  636. offy *= Offy;
  637. m_stage.To(p.X + offx, p.Y + offy);
  638. }
  639. #endregion
  640. #region Preview
  641. private void btnPreview_Click(object sender, EventArgs e)
  642. {
  643. PreviewPure.StartPreiew(sender as Button);
  644. }
  645. private TUCamera.TUCamera _camera;
  646. private Bitmap _imgNow;
  647. protected void StartCapture()
  648. {
  649. if (_camera != null)
  650. {
  651. // 开启预览
  652. _camera.m_bufHandler += CallbackDraw;
  653. _camera.StartWaitForFrame();
  654. }
  655. }
  656. public void StopCapture()
  657. {
  658. if (_camera != null)
  659. {
  660. // 开启预览
  661. _camera.m_bufHandler -= CallbackDraw;
  662. _camera.StopWaitForFrame();
  663. }
  664. }
  665. private void CallbackDraw(Bitmap obj)
  666. {
  667. var bmp = (Bitmap)obj.Clone();
  668. if (bmp.PixelFormat == PixelFormat.Format8bppIndexed)
  669. {
  670. ColorPalette palette = bmp.Palette;
  671. for (int i = 0; i < 256; i++)
  672. {
  673. palette.Entries[i] = Color.FromArgb(i, i, i);
  674. }
  675. bmp.Palette = palette;
  676. }
  677. if (_shootFlag)
  678. CatchShoot(bmp);
  679. else
  680. {
  681. try
  682. {
  683. _imgNow = (Bitmap)bmp.Clone();
  684. PreviewPure.ShowPrieview(bmp);
  685. }
  686. catch (Exception ex)
  687. {
  688. Console.WriteLine(ex.StackTrace, ex.Message);
  689. }
  690. }
  691. }
  692. #endregion
  693. #region Save
  694. string _dirRoot;
  695. string DirRoot
  696. {
  697. get => _dirRoot;
  698. set
  699. {
  700. _dirRoot = value;
  701. lblDirectory.Text = value;
  702. try
  703. {
  704. GetDriverInfo(value);
  705. }
  706. catch { }
  707. }
  708. }
  709. string _dirCurrent;
  710. private void btnChangDir_Click(object sender, EventArgs e)
  711. {
  712. if (_isWorking)
  713. return;
  714. var path = SelectFolder();
  715. if (string.IsNullOrEmpty(path)) return;
  716. DirRoot = path;
  717. }
  718. public string SelectFolder()
  719. {
  720. FolderBrowserDialog dialog = new FolderBrowserDialog();
  721. if (dialog.ShowDialog() == DialogResult.OK)
  722. {
  723. if (string.IsNullOrEmpty(dialog.SelectedPath))
  724. {
  725. // System.Windows.MessageBox.Show("文件夹路径不能为空", "提示");
  726. return null;
  727. }
  728. else
  729. return dialog.SelectedPath;
  730. }
  731. else return null;
  732. }
  733. /// <summary>
  734. /// 读取硬盘信息
  735. /// </summary>
  736. /// <param name="disk">盘符</param>
  737. public void GetDriverInfo(string disk)
  738. {
  739. long lsum = 0, ldr = 0;
  740. long gb = 1024 * 1024 * 1024;
  741. DriveInfo drive = new DriveInfo(disk);
  742. lsum = drive.TotalSize / gb;
  743. ldr = drive.TotalFreeSpace / gb;
  744. lblDisk.Width = (int)(lblDisk.Parent.Width - lblDisk.Parent.Width * ldr / lsum);
  745. }
  746. public string Save(Bitmap img)
  747. {
  748. var time = DateTime.Now.ToString("yyyyMMddHHmmss");//日期时间
  749. var id = _workSampleIndex + 1;//工位号
  750. var x = m_stage.X;//坐标x
  751. var y = m_stage.Y;//坐标y
  752. var i = _workScanIndex + 1;//图序号
  753. var stage = _stageSettingName;//样品台名称
  754. var fileName = _dirCurrent + "\\" + string.Format("{0}_{1}_{2}_{3}_{4:f2}_{5:f2}.jpg", time, i, stage, id, x, y);
  755. img.Save(fileName, ImageFormat.Jpeg);
  756. return fileName;
  757. }
  758. /// <summary>
  759. /// 创建工作目录
  760. /// </summary>
  761. public void NewWorkDir()
  762. {
  763. this.Invoke(new Action(() =>
  764. {
  765. _dirCurrent = DirRoot + "\\" + DateTime.Now.ToString("yyyyMMddHHmmss");// + "_" + cmbSampleStageList.Text;
  766. Directory.CreateDirectory(_dirCurrent);
  767. }));
  768. }
  769. #endregion
  770. #region Ai Api
  771. AiControl aicontrol;
  772. int _resultFlag = -1;
  773. void InitAi(string dir)
  774. {
  775. aicontrol = new AiControl(dir);
  776. aicontrol.CompleteBatchEvent += Aicontrol_CompleteBatchEvent;
  777. aicontrol.CompleteAllEvent += Aicontrol_CompleteAllEvent;
  778. }
  779. void Aicontrol_CompleteAllEvent(string result)
  780. {
  781. //Console.WriteLine("CompleteAllEvent");
  782. Console.WriteLine("全部完成,结果:" + result);
  783. _resultCmpAll.Add(result);
  784. this.Invoke(new Action(() =>
  785. {
  786. lblResult.Text = JsonHelper.ParseResultString(result);
  787. }));
  788. //ResultList.Add(_resultFlag, resultfilename);
  789. _resultFlag = -1;
  790. //生成报告
  791. }
  792. void Aicontrol_CompleteBatchEvent(List<string> batchfilenames)
  793. {
  794. foreach (var file in batchfilenames)
  795. {
  796. try
  797. {
  798. var result = _resultList.First((r) => r.FileName == file);
  799. _scanGird.SetDone(result.ScanId);
  800. result.Done = true;
  801. }
  802. catch
  803. {
  804. Console.WriteLine("获取结果时发生错误");
  805. }
  806. }
  807. Console.WriteLine("批次完成");
  808. }
  809. void EndGrade(int flag)
  810. {
  811. _resultFlag = flag;
  812. aicontrol.EndGrade();
  813. }
  814. void WaitAiCompleteAll()
  815. {
  816. while (_resultFlag != -1)
  817. {
  818. if (!_isWorking && !_offlineWorking)
  819. _resultFlag = -1;
  820. Thread.Sleep(50);
  821. }
  822. }
  823. #endregion
  824. #region Ai Operate
  825. List<ResultModel> _resultList = new List<ResultModel>();
  826. int _resultLookId = -1;
  827. int _resultSampleSelect = -1;
  828. int _resultScanSelect = -1;
  829. List<string> _resultCmpAll = new List<string>();
  830. ResultModel ResultSelect => _resultList.FirstOrDefault((r) => r.ResultId == _resultLookId && r.SampleId == _resultSampleSelect);
  831. private void ClearResult()
  832. {
  833. _resultList = new List<ResultModel>();
  834. _resultLookId = -1;
  835. _resultSampleSelect = -1;
  836. _resultScanSelect = -1;
  837. _resultCmpAll = new List<string>();
  838. }
  839. private void btnLookBack_Click(object sender, EventArgs e)
  840. {
  841. if (_resultLookId < 1)
  842. return;
  843. try
  844. {
  845. PreviewPure.ShowImage(ResultSelect.File, "查看原图");
  846. }
  847. catch { }
  848. }
  849. private void btnAnalysis_Click(object sender, EventArgs e)
  850. {
  851. if (_resultLookId < 1)
  852. return;
  853. var file = aicontrol.GetImageProcess(ResultSelect.File);
  854. try
  855. {
  856. PreviewPure.ShowImage(file, "分析过程");
  857. }
  858. catch { }
  859. }
  860. private void ShowResult()
  861. {
  862. if (_resultLookId < 1)
  863. {
  864. Console.WriteLine("尚未分析");
  865. return;
  866. }
  867. var result = ResultSelect;
  868. if (result == null || string.IsNullOrEmpty(result.File)) return;
  869. var str = aicontrol.GetImageTestResult(ResultSelect.File);
  870. ConsoleResult(string.IsNullOrEmpty(str) ? "没有结果" : str);
  871. }
  872. private void ConsoleResult(string msg)
  873. {
  874. lblResult.Text = msg;
  875. }
  876. private void UpdateScanGridByResult(int sampleId)
  877. {
  878. try
  879. {
  880. var list = _resultList.Where((r) => r.SampleId == sampleId).ToList();
  881. _resultSampleSelect = sampleId;
  882. _scanGird.Reset();
  883. foreach (var item in list)
  884. {
  885. if (_resultCmpAll[sampleId].Contains(item.FileName))
  886. _scanGird.SetResult(item.ScanId, item.ResultId);
  887. else if (item.Done)
  888. {
  889. _scanGird.SetDone(item.ScanId, item.ResultId);
  890. }
  891. else
  892. {
  893. _scanGird.SetDoning(item.ScanId, item.ResultId);
  894. }
  895. }
  896. lblResult.Text = JsonHelper.ParseResultString(_resultCmpAll[sampleId]);
  897. }
  898. catch { }
  899. }
  900. private void btnLocate_Click(object sender, EventArgs e)
  901. {
  902. if (!_isWorking)
  903. {
  904. if (_resultSampleSelect > -1 && _resultScanSelect > -1)
  905. ToScanPoint(_resultSampleSelect, _resultScanSelect);
  906. }
  907. }
  908. private void btnReport_Click(object sender, EventArgs e)
  909. {
  910. var result = new List<string>();
  911. AutoAnalysisReportDialog reportDialog = new AutoAnalysisReportDialog(this, "自动分析", result);
  912. if (reportDialog.hasModule)
  913. {
  914. reportDialog.StartPosition = FormStartPosition.CenterScreen;
  915. reportDialog.ExportReport = ExportReport;
  916. reportDialog.ShowDialog();
  917. }
  918. else
  919. {
  920. reportDialog = null;
  921. }
  922. }
  923. void ExportReport()
  924. { //获取word书签与excel单元格的关系,以字典方式存储
  925. List<mic_module_infos> infos = mic_module_infos_BLL.FindAll().FindAll(a => a.analyze_classify == this.analyzeSettingModel.analyzeClassify);
  926. Dictionary<string, string> tagInfos = new Dictionary<string, string>();
  927. if (infos != null && infos.Count > 0)
  928. {
  929. foreach (mic_module_infos info in infos)
  930. {
  931. tagInfos.Add(info.tag_name, info.cell_position);
  932. }
  933. }
  934. List<List<string>> inclusionList = new List<List<string>>();
  935. List<string> inclusionHead = new List<string>();
  936. List<Bitmap> bitList = new List<Bitmap>();
  937. for (int i = 0; i < _resultCmpAll.Count; i++)
  938. {
  939. var item = _resultCmpAll[i];
  940. var list = new List<string>();
  941. var rStr = JsonHelper.ParseResultString(item);
  942. list.Add("样品" + (i + 1) + ", 测试结果:");
  943. list.Add(rStr);
  944. inclusionList.Add(list);
  945. if (string.IsNullOrEmpty(rStr)) continue;
  946. list = rStr.Split(';').ToList();
  947. var dict = JsonHelper.ParseResultArray(item);
  948. foreach (var head in list)
  949. {
  950. var list1 = dict[head];
  951. foreach (var f in list1)
  952. {
  953. var list2 = new List<string>();
  954. list2.Add(head);
  955. list2.Add(f);
  956. inclusionList.Add(list2);
  957. }
  958. }
  959. }
  960. _app.CreateAnalysisReport(AnalyzeSettingModel, inclusionList, bitList, tagInfos);
  961. }
  962. #endregion
  963. #region Offline work
  964. bool _offlineWorking = false;
  965. string _srcDir = "";
  966. List<string> _srcList = new List<string>();
  967. double _x;
  968. double _y;
  969. void InitOfflineTest()
  970. {
  971. }
  972. private void btnOfflineTest_Click(object sender, EventArgs e)
  973. {
  974. if (_offlineWorking)
  975. {
  976. StopWorkOffline();
  977. btnOfflineTest.Text = "脱机运行";
  978. return;
  979. }
  980. _srcDir = SelectFolder();
  981. if (string.IsNullOrEmpty(_srcDir))
  982. return;
  983. _srcList = Directory.GetFiles(_srcDir).ToList();
  984. if (string.IsNullOrEmpty(_dirRoot))
  985. {
  986. MessageBox.Show("Please select a dir first.");
  987. return;
  988. }
  989. StartWorkOffline(); btnOfflineTest.Text = "停止";
  990. }
  991. void StartWorkOffline()
  992. {
  993. _offlineWorking = true;
  994. _workSampleIndex = 0;
  995. _workScanIndex = 0;
  996. NewWorkDir();
  997. InitAi(_dirCurrent);
  998. //_sampleStage.Reset();
  999. new Thread(RunTimeOffline).Start();
  1000. }
  1001. void StopWorkOffline()
  1002. {
  1003. _offlineWorking = false;
  1004. }
  1005. private void RunTimeOffline()
  1006. {
  1007. while (_offlineWorking)
  1008. {
  1009. if (_srcList.Count < NumCol * NumRow * (_workSampleIndex + 1))
  1010. {
  1011. _offlineWorking = false;
  1012. return;
  1013. }
  1014. _x = _stageSettingNow.WorkPoits[_workSampleIndex].X * 1000;
  1015. _y = _stageSettingNow.WorkPoits[_workSampleIndex].Y * 1000;
  1016. //_scanGird.Reset();
  1017. //_sampleStage.SetState(_sampleIndex, 2);
  1018. Console.WriteLine("样品" + (_workSampleIndex + 1) + "开始");
  1019. // aicontrol.StartAndSetGradeParam(cat, item, json, 100, 0.2755);
  1020. OfflineWorkflow();
  1021. EndGrade(_workSampleIndex);
  1022. Console.WriteLine("扫描完成");
  1023. WaitAiCompleteAll();
  1024. //_sampleStage.SetState(_sampleIndex, 3);
  1025. _workSampleIndex++;
  1026. //_offlineWorking = false;
  1027. if (_workSampleIndex >= _stageSettingNow.WorkPoits.Count)
  1028. _offlineWorking = false;
  1029. }
  1030. }
  1031. private void OfflineWorkflow()
  1032. {
  1033. var offx = _stageSettingNow.Width * 1000 / NumCol;
  1034. var offy = _stageSettingNow.Height * 1000 / NumRow;
  1035. for (int i = _workScanIndex; i < NumCol * NumRow && _offlineWorking; i++)
  1036. {
  1037. _workScanIndex = i;
  1038. int r = i / NumCol;
  1039. int c = i % NumCol;
  1040. if (i == 0) ;
  1041. else if (c == 0)
  1042. _y += offy;
  1043. else if (r % 2 == 0)
  1044. _x += offx;
  1045. else
  1046. _x -= offx;
  1047. Thread.Sleep(300);
  1048. aicontrol.PostFileName(CopyFile());
  1049. //_scanGird.SetDone(r * NumCol + c);
  1050. }
  1051. _workScanIndex = 0;
  1052. }
  1053. private string CopyFile()
  1054. {
  1055. var file = _srcList[_workScanIndex + NumCol * NumRow * _workSampleIndex];
  1056. var disFile = CreateFileOffline();
  1057. File.Copy(file, _dirCurrent + "\\" + disFile);
  1058. return disFile;
  1059. }
  1060. private string CreateFileOffline()
  1061. {
  1062. var time = DateTime.Now.ToString("yyyyMMddHHmmss");//日期时间
  1063. var id = _workSampleIndex;//工位号
  1064. var i = _workScanIndex + 1;//图序号
  1065. var stage = _stageSettingName;//样品台名称
  1066. var fileName = string.Format("{0}_{1}_{2}_{3}_{4}_{5}.jpg", time, i, stage, id, _x, _y);
  1067. return fileName;
  1068. }
  1069. #endregion
  1070. #region Stage Event
  1071. public void OnUpdatePosition()
  1072. {
  1073. }
  1074. public void OnTimeoutConnect()
  1075. {
  1076. btnStart.Enabled = false;
  1077. StopWork();
  1078. }
  1079. public void OnErrorSend()
  1080. {
  1081. }
  1082. #endregion
  1083. private void cmbScanMode_SelectedIndexChanged(object sender, EventArgs e)
  1084. {
  1085. _mode = cmbScanMode.SelectedIndex;
  1086. }
  1087. private void cmbAutoFocusParm_SelectedIndexChanged(object sender, EventArgs e)
  1088. {
  1089. int.TryParse(cmbAutoFocusParm.Text, out _focusInterval);
  1090. }
  1091. /// <summary>
  1092. /// 是否包含胶体
  1093. /// 1、全胶体
  1094. /// 2、部分胶体
  1095. /// 3、无胶体
  1096. /// </summary>
  1097. /// <param name="source">源图像</param>
  1098. /// <returns></returns>
  1099. private unsafe int CheckPicBoundary(Bitmap source)
  1100. {
  1101. int type = 3;
  1102. Mat gray = null;
  1103. try
  1104. {
  1105. var mat = BitmapConverter.ToMat(source);
  1106. if (mat.Channels() == 3)
  1107. gray = mat.CvtColor(ColorConversionCodes.BGR2GRAY);
  1108. else gray = mat;
  1109. gray.ForEachAsByte(this.Gray_ForEachAsByte);
  1110. OpenCvSharp.Point leftTop = new OpenCvSharp.Point(0, 0);
  1111. OpenCvSharp.Point rightTop = new OpenCvSharp.Point(gray.Width - 1, 0);
  1112. OpenCvSharp.Point leftBottom = new OpenCvSharp.Point(0, gray.Height - 1);
  1113. OpenCvSharp.Point rightBottom = new OpenCvSharp.Point(gray.Width - 1, gray.Height - 1);
  1114. byte leftTopV = gray.At<byte>(0, 0);
  1115. byte rightTopV = gray.At<byte>(0, gray.Width - 1);
  1116. byte leftBottomV = gray.At<byte>(gray.Height - 1, 0);
  1117. byte rightBottomV = gray.At<byte>(gray.Height - 1, gray.Width - 1);
  1118. Rect rect;
  1119. int leftTopNum = 0, rightTopNum = 0, leftBottomNum = 0, rightBottomNum = 0;
  1120. if (leftTopV == 0) leftTopNum = Cv2.FloodFill(gray, leftTop, new Scalar(0), out rect, null, null, FloodFillFlags.Link8);
  1121. if (rightTopV == 0) rightTopNum = Cv2.FloodFill(gray, rightTop, new Scalar(0), out rect, null, null, FloodFillFlags.Link8);
  1122. if (leftBottomV == 0) leftBottomNum = Cv2.FloodFill(gray, leftBottom, new Scalar(0), out rect, null, null, FloodFillFlags.Link8);
  1123. if (rightBottomV == 0) rightBottomNum = Cv2.FloodFill(gray, rightBottom, new Scalar(0), out rect, null, null, FloodFillFlags.Link8);
  1124. if (leftTopNum == 0 && rightTopNum == 0 && leftBottomNum == 0 && rightBottomNum == 0)
  1125. {
  1126. type = 3;
  1127. }
  1128. else if (leftTopNum > 0 && rightTopNum > 0 && leftBottomNum > 0 && rightBottomNum > 0)
  1129. {
  1130. type = 1;
  1131. }
  1132. else
  1133. {
  1134. if (leftTopNum > 10000 || rightTopNum > 10000 || leftBottomNum > 10000 || rightBottomNum > 10000)
  1135. {
  1136. type = 2;
  1137. }
  1138. }
  1139. }
  1140. catch (Exception)
  1141. {
  1142. }
  1143. finally
  1144. {
  1145. if (gray != null)
  1146. {
  1147. gray.Dispose();
  1148. GC.Collect();
  1149. }
  1150. }
  1151. return type;
  1152. }
  1153. private unsafe void Gray_ForEachAsByte(byte* value, int* position)
  1154. {
  1155. int y = position[0];
  1156. int x = position[1];
  1157. if (*value <= 90)
  1158. {
  1159. *value = 0;
  1160. }
  1161. else
  1162. {
  1163. *value = 255;
  1164. }
  1165. }
  1166. }
  1167. }