using System; using System.Globalization; using System.IO; using System.Threading.Tasks; using System.Windows; using Cognex.VisionPro; using Cognex.VisionPro.ToolBlock; using Plugins.Vpp.Converters; using Plugins.Vpp.Views; using TeamAAS.Camera.Images; using TeamAAS.Vision; using TeamAAS.Vision.Calibration.Interfaces; namespace Plugins.Vpp.Engines { /// /// VisionPro 引擎:基于 UCDispVpp 多画面控件(VppWindow 网格 + 双击放大)。 /// 实现 TeamAAS.Vision.IVisualEngine 抽象契约;引擎 SDK(Cognex)只被本插件引用。 /// 同时实现 :为标定算法提供"给图取特征点"能力, /// 通过一个 Cognex (约定输入 InputImage、输出 Found/Point)完成。 /// public class VisionProEngine : IVisualEngine, ICalibrationVisionProvider { public string EngineName => "VisionPro9.0"; // 标定工具(Cognex ToolBlock)与其持久化引用(.vpp 路径)。 private CogToolBlock _calibTool; private string _toolRef; public FrameworkElement GetMainView() { return UCDispVpp.Instance; } public void ApplyHomeLayout(int frameCount, int arrange) { // RowColNumber:{画面总数, 排列方式}——内部按最优行列铺设 VppWindow 网格 // frameCount=0 时清空画面区(主页面不显示画面框) UCDispVpp.Instance.RowColNumber = new[] { frameCount, arrange }; } public FrameworkElement GetCalibrationView() { return new VppCalibrationPage(); } /// 设置指定画面框的标题(画面名称);index 越界时静默忽略。 public void SetFrameCaption(int index, string name) { if (index < 0 || UCDispVpp.Instance.vppWindow.Count <= index) return; UCDispVpp.Instance.vppWindow[index].SetCaption(name); } /// 设置指定画面框的状态圆点显隐;index 越界时静默忽略。 public void SetFrameDotVisible(int index, bool visible) { if (index < 0 || UCDispVpp.Instance.vppWindow.Count <= index) return; UCDispVpp.Instance.vppWindow[index].SetStatusDotVisible(visible); } #region ICalibrationVisionProvider /// 当前标定工具句柄(Cognex CogToolBlock)。 public object CurrentTool => _calibTool; /// 标定工具持久化引用(.vpp 路径)。 public string ToolRef { get { return _toolRef; } set { _toolRef = value; } } /// /// 在图像上运行标定 ToolBlock,返回特征点像素坐标。 /// 约定:ToolBlock 输入终端 "InputImage",输出终端 "Found"(bool)、"Point"(字符串 "x,y[,angle]")。 /// public Task<(bool found, double px, double py, double angle)> FindCalibPoint(GenImage image) { return Task.Run(() => { try { if (_calibTool == null || image == null) return (false, 0d, 0d, 0d); ICogImage cog = GenImageConverter.ToCogImage(image); if (cog == null) return (false, 0d, 0d, 0d); var input = _calibTool.Inputs["InputImage"]; if (input != null) input.Value = cog; _calibTool.Run(); CogToolBlockTerminalCollection outputs = _calibTool.Outputs; var foundTerminal = outputs["Found"]; bool found = foundTerminal != null && foundTerminal.Value != null && Convert.ToBoolean(foundTerminal.Value); if (!found) return (false, 0d, 0d, 0d); double px = 0, py = 0, angle = 0; var pointTerminal = outputs["Point"]; if (pointTerminal != null && pointTerminal.Value != null) { ParsePoint(pointTerminal.Value, ref px, ref py, ref angle); } return (true, px, py, angle); } catch { return (false, 0d, 0d, 0d); } }); } /// 畸变校正:VisionPro 引擎暂原样返回(如需棋盘格校正后续在此接入)。 public Task Undistort(GenImage image) { return Task.FromResult(image); } /// 从 .vpp 引用加载标定 ToolBlock;引用为空或加载失败时新建空 ToolBlock。 public void LoadTool(string toolRef) { _toolRef = toolRef; _calibTool = null; try { if (!string.IsNullOrEmpty(toolRef) && File.Exists(toolRef)) { _calibTool = CogSerializer.LoadObjectFromFile(toolRef) as CogToolBlock; } } catch { _calibTool = null; } if (_calibTool == null) _calibTool = new CogToolBlock(); } /// 将当前标定 ToolBlock 保存到目录下的 CalibTool.vpp,返回该路径作为持久化引用。 public string SaveTool(string directory) { if (_calibTool == null) return _toolRef; try { if (!Directory.Exists(directory)) Directory.CreateDirectory(directory); string path = Path.Combine(directory, "CalibTool.vpp"); CogSerializer.SaveObjectToFile(_calibTool, path); _toolRef = path; return path; } catch { return _toolRef; } } private static void ParsePoint(object value, ref double px, ref double py, ref double angle) { string s = value.ToString(); if (string.IsNullOrWhiteSpace(s)) return; string[] items = s.Split(','); if (items.Length >= 2 && double.TryParse(items[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out double x) && double.TryParse(items[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out double y)) { px = x; py = y; } if (items.Length >= 3 && double.TryParse(items[2].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out double a)) { angle = a; } } #endregion } }