using AiControlRequest; using OpenCvSharp; using OpenCvSharp.Extensions; using PaintDotNet; using PaintDotNet.Base.CommTool; using PaintDotNet.DbOpreate.DbBll; using PaintDotNet.DbOpreate.DbModel; using PaintDotNet.ImageCollect; using StageController; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using TUCamera; using static AiControlRequest.AiControl; namespace Metis.AutoAnalysis { internal partial class AutoAnalysisDialog : FloatingToolForm, IStageEvent { /// /// 样品台展示控件 /// SampleStageControl _samplesControl; Dictionary _stageSettingList; SampleStageModel _stageSettingNow; string _stageSettingName; /// /// 结果展示控件 /// ScanGridControl _scanGird; AxisController m_stage; private double m_PxLength; Dictionary ResultList = new Dictionary(); protected int ConvertUMToPX(double length) { return (int)(length / m_PxLength); } protected double ConvertPXToUm(double length) { return length * m_PxLength; } public int VisionWidthPixel; public int VisionHeightPixel; public double VisionWidth; public double VisionHeight; public int NumRow; public int NumCol; private AppWorkspace _app; public AutoAnalysisDialog(AppWorkspace app) { _app = app; InitializeComponent(); Startup.instance.rules.TryGetValue(MeasurementUnit.Micron, out m_PxLength); _scanGird = new ScanGridControl(); _scanGird.MouseDown += _scanGird_MouseDown; pnlScanGrid.Controls.Add(_scanGird); InitSmapleStageControl(); DirRoot = @"D:\AiTest";//Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory); _camera = TUCameraManager.GetInstance().GetCurrentCamera(); var size = _camera.GetResolution(); VisionWidthPixel = size.Width == 0 ? 1000 : size.Width; VisionHeightPixel = size.Height == 0 ? 1000 : size.Height; VisionWidth = ConvertPXToUm(VisionWidthPixel); VisionHeight = ConvertPXToUm(VisionHeightPixel); lblImageSize.Text = string.Format("{0:f0}*{1:f0}", VisionWidthPixel, VisionHeightPixel); SetAnalyzeModelFromXml("自动分析"); } #region Load Close private void AutoAnalysisDialog_Load(object sender, EventArgs e) { CameraConfigs.GetInstance().CameraParamInit(); _stageSettingList = SampleStageManager.GetAll(); foreach (var s in _stageSettingList.Keys) cmbSampleStageList.Items.Add(s); if (cmbSampleStageList.Items.Count > 0) cmbSampleStageList.SelectedIndex = 0; cmbScanMode.SelectedIndex = 0; cmbAutoFocusParm.SelectedIndex = 0; tmrUpdateUI.Start(); tmrUpdateUI.Tick += TmrUpdateUI_Tick; UpdateUserList(); StartCapture(); InitStage(); InitOfflineTest(); InitCheckConfig(); } int[] _detectParams = new int[3]; private CheckConfigModel _checkconfig; private void CheckItemChange(string str) { for (int i = 0; i < 3; i++) _detectParams[i] = int.Parse(str.Split(',')[i]); } private void InitCheckConfig() { try { string CheckconfigPath = @"Automation\checkitem\checkconfig.xml"; _checkconfig = XmlSerializeHelper.Load(CheckconfigPath); cmbProjuctSelect.DropDownStyle = ComboBoxStyle.DropDownList; foreach (var item in _checkconfig.Items) { cmbProjuctSelect.Items.Add(item.Name); cmbProjuctSelect.SelectedIndex = 0; } } catch { MessageBox.Show("请检查\"\\Automation\\checkitem\\checkconfig.xml\"文件是否有错误。", "检测配置文件错误"); } } /// /// 更新控件状态 /// private void TmrUpdateUI_Tick(object sender, EventArgs e) { grpStage.Enabled = !_isWorking; grpFocus.Enabled = !_isWorking; grpStageInfo.Enabled = !_isWorking; grpStageDisplay.Enabled = !_isWorking; grpWorkOperate.Enabled = m_stage.IsOpen; grpAiOperate.Enabled = !_isWorking || _pause; grpRange.Enabled = !_isWorking; btnLocate.Enabled = !_isWorking & m_stage.IsOpen; btnLookBack.Enabled = _workDone || _pause; btnAnalysis.Enabled = _workDone || _pause; btnReport.Enabled = _workDone; btnStart.Text = !_isWorking || _pause ? "开始" : "暂停"; btnStop.Enabled = _isWorking; cmbProjuctSelect.Enabled = !_isWorking; if (_isWorking) { _resultScanSelect = -1; } } private void AutoAnalysisDialog_FormClosing(object sender, FormClosingEventArgs e) { StopCapture(); StopWork(); } public void InitStage() { m_stage = AxisController.GetInstance(); pnlTest.Width = 0; if (!m_stage.IsOpen) { // MessageBox.Show(PdnResources.GetString("Message.AxisController.NotConnected")); //grpWorkOperate.Enabled = false; return; } m_stage.SetWorkspeedXY(); var dialog = TransferProgressDialog.CreatDialog("平台复位", "复位中...", null, "Stop"); m_stage.ResetStage( () => { this.Invoke(new Action(dialog.Close)); }); dialog.ShowDialog(); } #endregion private void cmbSampleStageList_SelectedIndexChanged(object sender, EventArgs e) { _stageSettingNow = _stageSettingList[cmbSampleStageList.Text]; _stageSettingName = cmbSampleStageList.Text; UpdateSmapleStageControl(); BuildTableList(); var hc = Math.Ceiling(_stageSettingNow.Width * 1000 / VisionWidth); var vc = Math.Ceiling(_stageSettingNow.Height * 1000 / VisionHeight); nupHorizon.Value = (decimal)hc; nupVertical.Value = (decimal)vc; ClearResult(); } #region ScanGrid Display private void nupHorizon_ValueChanged(object sender, EventArgs e) { var colN = (int)nupHorizon.Value; var rowN = (int)nupVertical.Value; if (colN != 0 && rowN != 0) UpdateScanGrid(colN, rowN); else { return; } var width = ConvertUMToPX(_stageSettingNow.Width * 1000 / colN); var height = ConvertUMToPX(_stageSettingNow.Height * 1000 / rowN); lblStageSize.Text = string.Format("{0:f0}*{1:f0}", width, height); } private void UpdateScanGrid(int c, int r) { lblTotal.Text = (c * r).ToString(); NumCol = c; NumRow = r; _scanGird.NumCol = c; _scanGird.NumRow = r; _scanGird.VsnWitch = VisionWidth; _scanGird.VsnHeight = VisionHeight; _scanGird.InitGrid(_stageSettingNow); } private void _scanGird_MouseDown(object sender, MouseEventArgs e) { _resultLookId = _scanGird.GetHitId(e.X, e.Y); _resultScanSelect = _scanGird.GetIndex(e.X, e.Y); ShowResult(); } #endregion #region SampleStage void InitSmapleStageControl() { _samplesControl = new SampleStageControl(); _samplesControl.OnSelectChanged += (value) => { UpdateInfoTable(value); // if (_workDone) UpdateScanGridByResult(value); }; pnlStageDisplay.Controls.Add(_samplesControl); } private void UpdateSmapleStageControl() { _samplesControl.Update(_stageSettingNow); } private void ResetSmapleState() { for (int i = 0; i < _tables.Length; i++) { var table = _tables[i]; if (table == null) _samplesControl.SetState(i, 0); else _samplesControl.SetState(i, 1); } } #endregion #region User List _userList; private void UpdateUserList() { cmbUser.Items.Clear(); _userList = SampleStageManager.GetUsers(); foreach (var s in _userList) cmbUser.Items.Add(s); if (cmbUser.Items.Count > 0) cmbUser.SelectedIndex = 0; } private void btnAddUser_Click(object sender, EventArgs e) { var form = new AddUser() { CallOK = AddUser }; form.TopMost = true; form.ShowDialog(); } private void AddUser(string s) { if (_userList.Contains(s)) return; _userList.Insert(0, s); SampleStageManager.SaveUsers(_userList); UpdateUserList(); } private void DelUser(string s) { _userList.Remove(s); SampleStageManager.SaveUsers(_userList); UpdateUserList(); } private void btnDelUser_Click(object sender, EventArgs e) { DelUser(cmbUser.Text); } #endregion #region Information string[] _infos; DataTable[] _tables; char _spliter = ';'; string GetUser() { return cmbUser.Text; } void BuildTableList() { dgvStageInfo.DataSource = null; _tables = new DataTable[_stageSettingNow.WorkPoits.Count]; _infos = new string[_stageSettingNow.WorkPoits.Count]; } private void txbInfo_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { btnAddInfo_Click(null, null); } } private void btnAddInfo_Click(object sender, EventArgs e) { if (!_tables.Any((t) => t == null)) { MessageBox.Show("所有工位已经添加完成"); return; } var user = GetUser(); if (string.IsNullOrEmpty(user)) { MessageBox.Show("请先添加检测员。"); return; } var infostr = txbInfo.Text; if (string.IsNullOrEmpty(infostr)) return; txbInfo.Text = ""; var list = infostr.Split(_spliter); var sampleEditSelect = _tables.ToList().FindIndex((t) => t == null); _samplesControl.SelectIndex = sampleEditSelect; var table = new DataTable(); table.Columns.Add("工位 ", typeof(string)); table.Columns.Add("样品信息 ", typeof(string)); table.Columns.Add("检测 ", typeof(bool)); table.Columns.Add("结果 ", typeof(string)); table.Columns.Add("检测员 ", typeof(string)); for (int i = 0; i < list.Length; i++) { var row = table.NewRow(); if (i == 0) row[0] = "#" + (sampleEditSelect + 1); int j = 1; row[j++] = list[i]; row[j++] = true; row[j++] = ""; row[j++] = user; table.Rows.Add(row); } _tables[sampleEditSelect] = table; _infos[sampleEditSelect] = infostr; _samplesControl.SetState(sampleEditSelect, 1); UpdateInfoTable(sampleEditSelect); } private void UpdateInfoTable(int i) { var table = _tables[i]; dgvStageInfo.DataSource = table; } private void btnDelInfo_Click(object sender, EventArgs e) { if (_samplesControl.SelectIndex < 0) return; var i = _samplesControl.SelectIndex; _tables[i] = null; _infos[i] = null; dgvStageInfo.DataSource = null; _samplesControl.SetState(i, 0); } private bool IsCheck(int id) { return (bool)dgvStageInfo.Rows[id].Cells[2].Value; } #endregion #region Work int _workSampleIndex; int _workScanIndex; bool _isWorking; bool _pause = false; bool _workDone; bool _isOnce = false; bool _restart = false; ResultModel _resultWorking; /// /// 聚焦间隔 /// int _focusInterval = 1; /// /// 蛇形扫描: 0:连续,1:间隔 /// int _mode = 0; private void btnStart_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(_dirRoot)) { MessageBox.Show("请选择"); return; } var str = cmbProjuctSelect.Text; if (string.IsNullOrEmpty(str)) { MessageBox.Show("检测项目不能为空"); return; } var item = _checkconfig.Items.First((i) => i.Name == str); CheckItemChange(item.Value); var table = _tables[0]; if (table == null) { MessageBox.Show("请添加样品信息。"); return; } var hasCheck = false; for (int i = 0; i < table.Rows.Count; i++) { hasCheck |= (bool)table.Rows[i][2]; } if (!hasCheck) { MessageBox.Show("请选择检测项。"); return; } if (!_isWorking) { StartWork(); } else { if (_pause) { _restart = rdbReplayAll.Checked; _isWorking = !_restart; } else { } _pause = !_pause; } _isOnce = rdbOnlyCurrent.Checked; } private void btnStop_Click(object sender, EventArgs e) { StopWork(); } private void StartWork() { _workSampleIndex = 0; _workScanIndex = 0; _resultCmpAll = new List(); _resultList = new List(); NewWorkDir(); InitAi(_dirCurrent); Directory.Delete(_dirCurrent); _isWorking = true; ResetSmapleState(); new Thread(Runtime).Start(); } private void PauseWork() { _pause = true; } private void StopWork() { AutoFocusWorkflow.Stop(); _pause = false; _isWorking = false; } private void Runtime() { Console.WriteLine("In to work runtime"); while (_isWorking) { while (_pause) { Thread.Sleep(50); if (!_isWorking) break; } ToWorkStartPoint(_workSampleIndex); NewWorkDir(); aicontrol.GradePaht = _dirCurrent; var rule = Startup.instance.ruleDB; if (rule != null) { int mul = (int)rule.gain_multiple; double umperpx = (double)(rule.physical_length / (decimal)rule.pixel_length); // aicontrol.StartAndSetGradeParam(catagoryParam.Inclusion, itemParam.Inclusion, jsonParam.InclusionALL, mul, umperpx); aicontrol.StartAndSetGradeParam((catagoryParam)_detectParams[0], (itemParam)_detectParams[1], (jsonParam)_detectParams[2], mul, umperpx); } else { aicontrol.StartAndSetGradeParam((catagoryParam)_detectParams[0], (itemParam)_detectParams[1], (jsonParam)_detectParams[2], 1, 1); } _samplesControl.SetState(_workSampleIndex, 2); _scanGird.Reset(); //Scan ScanSampleWorkflow(); if (!_isWorking) break; _samplesControl.SetState(_workSampleIndex, 3); _resultFlag = _workSampleIndex + 1; EndGrade(_workSampleIndex); if (_workSampleIndex < _stageSettingNow.WorkPoits.Count - 1) ToWorkStartPoint(_workSampleIndex + 1); WaitAiCompleteAll(); _workSampleIndex++; if (_workSampleIndex >= _stageSettingNow.WorkPoits.Count) break; } Console.WriteLine("Out of work runtime."); //当全部扫码完成退出循环,_isWorking依然为true,则认为完成 _workDone = _isWorking; StopWork(); if (_restart) { _restart = false; StartWork(); } } private void ScanSampleWorkflow() { for (; _workScanIndex < NumCol * NumRow && _isWorking; _workScanIndex += 1 + _mode) { while (_pause) { Thread.Sleep(50); if (!_isWorking) return; } if (_isOnce) _pause = true; //Console.Write("Before To Next:"); m_stage.WaitMoveDone(); ToNext(Offx, Offy, _workScanIndex); _scanGird.SetDoning(_workScanIndex, _workScanIndex / (_mode + 1) + 1); _resultWorking = new ResultModel() { SampleId = _workSampleIndex, ScanId = _workScanIndex, ResultId = _workScanIndex / (_mode + 1) + 1 }; _resultList.Add(_resultWorking); if (rbtAutoFocus.Checked) { if ((_workScanIndex / (_mode + 1) + 1) % _focusInterval == 0) AutoFocusWorkflow.AutoFocusFast(m_stage, () => _imgNow); } SetShoot(); } _workScanIndex = 0; } bool _shootFlag = false; private void SetShoot() { _shootFlag = true; while (_isWorking && _shootFlag) { Thread.Sleep(10); } } private void CatchShoot(Bitmap img) { _shootFlag = false; _resultWorking.File = Save(img); var type = CheckPicBoundary(img); if (type == 3 || (type == 2 && _checkconfig.Border == 1)) aicontrol.PostFileName(_resultWorking.FileName); } class ResultModel { public int SampleId; public int ScanId = -1; public bool Done; //public string Result; string _file; public string File { get => _file; set { _file = value; var i = value.LastIndexOf('\\'); Dir = value.Substring(0, i + 1); FileName = value.Substring(i + 1); } } public string Dir; public string FileName; public int ResultId; } #endregion #region Move To float Offx => _stageSettingNow.Width * 1000 / NumCol; float Offy => _stageSettingNow.Height * 1000 / NumRow; /// /// 移动到开始位置 /// /// private void ToWorkStartPoint(int i) { var p = GetWorkStartPoint(i); m_stage.To(p.X, p.Y); } private PointF GetWorkStartPoint(int i) { var x = (_stageSettingNow.WorkPoits[i].X - _stageSettingNow.Width / 2) * 1000; var y = (_stageSettingNow.WorkPoits[i].Y - _stageSettingNow.Height / 2) * 1000; return new PointF(x, y); } private void ToNext(double offx, double offy, int i) { double x = 0, y = 0; int r = i / NumCol; int c = i % NumCol; if (_mode == 0) { if (i == 0) ; else if (c == 0) y = offy; else if (r % 2 == 0) x = offx; else x = -offx; } if (_mode == 1) { if (i == 0) ; else if (r % 2 == 0) { if (c == 0) { x = -offx; y = offy; } else if (c == 1) { x = offx; y = offy; } else x = 2 * offx; } else { if (c == 0) { x = offx; y = offy; } else if (c == 1) { x = -offx; y = offy; } else x = -2 * offx; } } m_stage.Move(x, y); // Console.Write("To Next:"); m_stage.WaitMoveDone(); } private void ToScanPoint(int sampleId, int scanId) { var p = GetWorkStartPoint(sampleId); float offx = scanId / NumCol % 2 == 0 ? scanId % NumCol : NumCol - scanId % NumCol - 1; float offy = (int)(scanId / NumCol); offx *= Offx; offy *= Offy; m_stage.To(p.X + offx, p.Y + offy); } #endregion #region Preview private void btnPreview_Click(object sender, EventArgs e) { PreviewPure.StartPreiew(sender as Button); } private TUCamera.TUCamera _camera; private Bitmap _imgNow; protected void StartCapture() { if (_camera != null) { // 开启预览 _camera.m_bufHandler += CallbackDraw; _camera.StartWaitForFrame(); } } public void StopCapture() { if (_camera != null) { // 开启预览 _camera.m_bufHandler -= CallbackDraw; _camera.StopWaitForFrame(); } } private void CallbackDraw(Bitmap obj) { var bmp = (Bitmap)obj.Clone(); if (bmp.PixelFormat == PixelFormat.Format8bppIndexed) { ColorPalette palette = bmp.Palette; for (int i = 0; i < 256; i++) { palette.Entries[i] = Color.FromArgb(i, i, i); } bmp.Palette = palette; } if (_shootFlag) CatchShoot(bmp); else { try { _imgNow = (Bitmap)bmp.Clone(); PreviewPure.ShowPrieview(bmp); } catch (Exception ex) { Console.WriteLine(ex.StackTrace, ex.Message); } } } #endregion #region Save string _dirRoot; string DirRoot { get => _dirRoot; set { _dirRoot = value; lblDirectory.Text = value; try { GetDriverInfo(value); } catch { } } } string _dirCurrent; private void btnChangDir_Click(object sender, EventArgs e) { if (_isWorking) return; var path = SelectFolder(); if (string.IsNullOrEmpty(path)) return; DirRoot = path; } public string SelectFolder() { FolderBrowserDialog dialog = new FolderBrowserDialog(); if (dialog.ShowDialog() == DialogResult.OK) { if (string.IsNullOrEmpty(dialog.SelectedPath)) { // System.Windows.MessageBox.Show("文件夹路径不能为空", "提示"); return null; } else return dialog.SelectedPath; } else return null; } /// /// 读取硬盘信息 /// /// 盘符 public void GetDriverInfo(string disk) { long lsum = 0, ldr = 0; long gb = 1024 * 1024 * 1024; DriveInfo drive = new DriveInfo(disk); lsum = drive.TotalSize / gb; ldr = drive.TotalFreeSpace / gb; lblDisk.Width = (int)(lblDisk.Parent.Width - lblDisk.Parent.Width * ldr / lsum); } public string Save(Bitmap img) { var time = DateTime.Now.ToString("yyyyMMddHHmmss");//日期时间 var id = _workSampleIndex + 1;//工位号 var x = m_stage.X;//坐标x var y = m_stage.Y;//坐标y var i = _workScanIndex + 1;//图序号 var stage = _stageSettingName;//样品台名称 var fileName = _dirCurrent + "\\" + string.Format("{0}_{1}_{2}_{3}_{4:f2}_{5:f2}.jpg", time, i, stage, id, x, y); img.Save(fileName, ImageFormat.Jpeg); return fileName; } /// /// 创建工作目录 /// public void NewWorkDir() { this.Invoke(new Action(() => { _dirCurrent = DirRoot + "\\" + DateTime.Now.ToString("yyyyMMddHHmmss");// + "_" + cmbSampleStageList.Text; Directory.CreateDirectory(_dirCurrent); })); } #endregion #region Ai Api AiControl aicontrol; int _resultFlag = -1; void InitAi(string dir) { aicontrol = new AiControl(dir); aicontrol.CompleteBatchEvent += Aicontrol_CompleteBatchEvent; aicontrol.CompleteAllEvent += Aicontrol_CompleteAllEvent; } void Aicontrol_CompleteAllEvent(string result) { //Console.WriteLine("CompleteAllEvent"); Console.WriteLine("全部完成,结果:" + result); _resultCmpAll.Add(result); this.Invoke(new Action(() => { lblResult.Text = JsonHelper.ParseResultString(result); })); //ResultList.Add(_resultFlag, resultfilename); _resultFlag = -1; //生成报告 } void Aicontrol_CompleteBatchEvent(List batchfilenames) { foreach (var file in batchfilenames) { try { var result = _resultList.First((r) => r.FileName == file); _scanGird.SetDone(result.ScanId); result.Done = true; } catch { Console.WriteLine("获取结果时发生错误"); } } Console.WriteLine("批次完成"); } void EndGrade(int flag) { _resultFlag = flag; aicontrol.EndGrade(); } void WaitAiCompleteAll() { while (_resultFlag != -1) { if (!_isWorking && !_offlineWorking) _resultFlag = -1; Thread.Sleep(50); } } #endregion #region Ai Operate List _resultList = new List(); int _resultLookId = -1; int _resultSampleSelect = -1; int _resultScanSelect = -1; List _resultCmpAll = new List(); ResultModel ResultSelect => _resultList.FirstOrDefault((r) => r.ResultId == _resultLookId && r.SampleId == _resultSampleSelect); private void ClearResult() { _resultList = new List(); _resultLookId = -1; _resultSampleSelect = -1; _resultScanSelect = -1; _resultCmpAll = new List(); } private void btnLookBack_Click(object sender, EventArgs e) { if (_resultLookId < 1) return; try { PreviewPure.ShowImage(ResultSelect.File, "查看原图"); } catch { } } private void btnAnalysis_Click(object sender, EventArgs e) { if (_resultLookId < 1) return; var file = aicontrol.GetImageProcess(ResultSelect.File); try { PreviewPure.ShowImage(file, "分析过程"); } catch { } } private void ShowResult() { if (_resultLookId < 1) { Console.WriteLine("尚未分析"); return; } var result = ResultSelect; if (result == null || string.IsNullOrEmpty(result.File)) return; var str = aicontrol.GetImageTestResult(ResultSelect.File); ConsoleResult(string.IsNullOrEmpty(str) ? "没有结果" : str); } private void ConsoleResult(string msg) { lblResult.Text = msg; } private void UpdateScanGridByResult(int sampleId) { try { var list = _resultList.Where((r) => r.SampleId == sampleId).ToList(); _resultSampleSelect = sampleId; _scanGird.Reset(); foreach (var item in list) { if (_resultCmpAll[sampleId].Contains(item.FileName)) _scanGird.SetResult(item.ScanId, item.ResultId); else if (item.Done) { _scanGird.SetDone(item.ScanId, item.ResultId); } else { _scanGird.SetDoning(item.ScanId, item.ResultId); } } lblResult.Text = JsonHelper.ParseResultString(_resultCmpAll[sampleId]); } catch { } } private void btnLocate_Click(object sender, EventArgs e) { if (!_isWorking) { if (_resultSampleSelect > -1 && _resultScanSelect > -1) ToScanPoint(_resultSampleSelect, _resultScanSelect); } } private void btnReport_Click(object sender, EventArgs e) { var result = new List(); AutoAnalysisReportDialog reportDialog = new AutoAnalysisReportDialog(this, "自动分析", result); if (reportDialog.hasModule) { reportDialog.StartPosition = FormStartPosition.CenterScreen; reportDialog.ExportReport = ExportReport; reportDialog.ShowDialog(); } else { reportDialog = null; } } void ExportReport() { //获取word书签与excel单元格的关系,以字典方式存储 List infos = mic_module_infos_BLL.FindAll().FindAll(a => a.analyze_classify == this.analyzeSettingModel.analyzeClassify); Dictionary tagInfos = new Dictionary(); if (infos != null && infos.Count > 0) { foreach (mic_module_infos info in infos) { tagInfos.Add(info.tag_name, info.cell_position); } } List> inclusionList = new List>(); List inclusionHead = new List(); List bitList = new List(); for (int i = 0; i < _resultCmpAll.Count; i++) { var item = _resultCmpAll[i]; var list = new List(); var rStr = JsonHelper.ParseResultString(item); list.Add("样品" + (i + 1) + ", 测试结果:"); list.Add(rStr); inclusionList.Add(list); if (string.IsNullOrEmpty(rStr)) continue; list = rStr.Split(';').ToList(); var dict = JsonHelper.ParseResultArray(item); foreach (var head in list) { var list1 = dict[head]; foreach (var f in list1) { var list2 = new List(); list2.Add(head); list2.Add(f); inclusionList.Add(list2); } } } _app.CreateAnalysisReport(AnalyzeSettingModel, inclusionList, bitList, tagInfos); } #endregion #region Offline work bool _offlineWorking = false; string _srcDir = ""; List _srcList = new List(); double _x; double _y; void InitOfflineTest() { } private void btnOfflineTest_Click(object sender, EventArgs e) { if (_offlineWorking) { StopWorkOffline(); btnOfflineTest.Text = "脱机运行"; return; } _srcDir = SelectFolder(); if (string.IsNullOrEmpty(_srcDir)) return; _srcList = Directory.GetFiles(_srcDir).ToList(); if (string.IsNullOrEmpty(_dirRoot)) { MessageBox.Show("Please select a dir first."); return; } StartWorkOffline(); btnOfflineTest.Text = "停止"; } void StartWorkOffline() { _offlineWorking = true; _workSampleIndex = 0; _workScanIndex = 0; NewWorkDir(); InitAi(_dirCurrent); //_sampleStage.Reset(); new Thread(RunTimeOffline).Start(); } void StopWorkOffline() { _offlineWorking = false; } private void RunTimeOffline() { while (_offlineWorking) { if (_srcList.Count < NumCol * NumRow * (_workSampleIndex + 1)) { _offlineWorking = false; return; } _x = _stageSettingNow.WorkPoits[_workSampleIndex].X * 1000; _y = _stageSettingNow.WorkPoits[_workSampleIndex].Y * 1000; //_scanGird.Reset(); //_sampleStage.SetState(_sampleIndex, 2); Console.WriteLine("样品" + (_workSampleIndex + 1) + "开始"); // aicontrol.StartAndSetGradeParam(cat, item, json, 100, 0.2755); OfflineWorkflow(); EndGrade(_workSampleIndex); Console.WriteLine("扫描完成"); WaitAiCompleteAll(); //_sampleStage.SetState(_sampleIndex, 3); _workSampleIndex++; //_offlineWorking = false; if (_workSampleIndex >= _stageSettingNow.WorkPoits.Count) _offlineWorking = false; } } private void OfflineWorkflow() { var offx = _stageSettingNow.Width * 1000 / NumCol; var offy = _stageSettingNow.Height * 1000 / NumRow; for (int i = _workScanIndex; i < NumCol * NumRow && _offlineWorking; i++) { _workScanIndex = i; int r = i / NumCol; int c = i % NumCol; if (i == 0) ; else if (c == 0) _y += offy; else if (r % 2 == 0) _x += offx; else _x -= offx; Thread.Sleep(300); aicontrol.PostFileName(CopyFile()); //_scanGird.SetDone(r * NumCol + c); } _workScanIndex = 0; } private string CopyFile() { var file = _srcList[_workScanIndex + NumCol * NumRow * _workSampleIndex]; var disFile = CreateFileOffline(); File.Copy(file, _dirCurrent + "\\" + disFile); return disFile; } private string CreateFileOffline() { var time = DateTime.Now.ToString("yyyyMMddHHmmss");//日期时间 var id = _workSampleIndex;//工位号 var i = _workScanIndex + 1;//图序号 var stage = _stageSettingName;//样品台名称 var fileName = string.Format("{0}_{1}_{2}_{3}_{4}_{5}.jpg", time, i, stage, id, _x, _y); return fileName; } #endregion #region Stage Event public void OnUpdatePosition() { } public void OnTimeoutConnect() { btnStart.Enabled = false; StopWork(); } public void OnErrorSend() { } #endregion private void cmbScanMode_SelectedIndexChanged(object sender, EventArgs e) { _mode = cmbScanMode.SelectedIndex; } private void cmbAutoFocusParm_SelectedIndexChanged(object sender, EventArgs e) { int.TryParse(cmbAutoFocusParm.Text, out _focusInterval); } /// /// 是否包含胶体 /// 1、全胶体 /// 2、部分胶体 /// 3、无胶体 /// /// 源图像 /// private unsafe int CheckPicBoundary(Bitmap source) { int type = 3; Mat gray = null; try { var mat = BitmapConverter.ToMat(source); if (mat.Channels() == 3) gray = mat.CvtColor(ColorConversionCodes.BGR2GRAY); else gray = mat; gray.ForEachAsByte(this.Gray_ForEachAsByte); OpenCvSharp.Point leftTop = new OpenCvSharp.Point(0, 0); OpenCvSharp.Point rightTop = new OpenCvSharp.Point(gray.Width - 1, 0); OpenCvSharp.Point leftBottom = new OpenCvSharp.Point(0, gray.Height - 1); OpenCvSharp.Point rightBottom = new OpenCvSharp.Point(gray.Width - 1, gray.Height - 1); byte leftTopV = gray.At(0, 0); byte rightTopV = gray.At(0, gray.Width - 1); byte leftBottomV = gray.At(gray.Height - 1, 0); byte rightBottomV = gray.At(gray.Height - 1, gray.Width - 1); Rect rect; int leftTopNum = 0, rightTopNum = 0, leftBottomNum = 0, rightBottomNum = 0; if (leftTopV == 0) leftTopNum = Cv2.FloodFill(gray, leftTop, new Scalar(0), out rect, null, null, FloodFillFlags.Link8); if (rightTopV == 0) rightTopNum = Cv2.FloodFill(gray, rightTop, new Scalar(0), out rect, null, null, FloodFillFlags.Link8); if (leftBottomV == 0) leftBottomNum = Cv2.FloodFill(gray, leftBottom, new Scalar(0), out rect, null, null, FloodFillFlags.Link8); if (rightBottomV == 0) rightBottomNum = Cv2.FloodFill(gray, rightBottom, new Scalar(0), out rect, null, null, FloodFillFlags.Link8); if (leftTopNum == 0 && rightTopNum == 0 && leftBottomNum == 0 && rightBottomNum == 0) { type = 3; } else if (leftTopNum > 0 && rightTopNum > 0 && leftBottomNum > 0 && rightBottomNum > 0) { type = 1; } else { if (leftTopNum > 10000 || rightTopNum > 10000 || leftBottomNum > 10000 || rightBottomNum > 10000) { type = 2; } } } catch (Exception) { } finally { if (gray != null) { gray.Dispose(); GC.Collect(); } } return type; } private unsafe void Gray_ForEachAsByte(byte* value, int* position) { int y = position[0]; int x = position[1]; if (*value <= 90) { *value = 0; } else { *value = 255; } } } }