VisionProEngine.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. using System;
  2. using System.Globalization;
  3. using System.IO;
  4. using System.Threading.Tasks;
  5. using System.Windows;
  6. using Cognex.VisionPro;
  7. using Cognex.VisionPro.ToolBlock;
  8. using Plugins.Vpp.Converters;
  9. using Plugins.Vpp.Views;
  10. using TeamAAS.Camera.Images;
  11. using TeamAAS.Vision;
  12. using TeamAAS.Vision.Calibration.Interfaces;
  13. namespace Plugins.Vpp.Engines
  14. {
  15. /// <summary>
  16. /// VisionPro 引擎:基于 UCDispVpp 多画面控件(VppWindow 网格 + 双击放大)。
  17. /// 实现 TeamAAS.Vision.IVisualEngine 抽象契约;引擎 SDK(Cognex)只被本插件引用。
  18. /// 同时实现 <see cref="ICalibrationVisionProvider"/>:为标定算法提供"给图取特征点"能力,
  19. /// 通过一个 Cognex <see cref="CogToolBlock"/>(约定输入 InputImage、输出 Found/Point)完成。
  20. /// </summary>
  21. public class VisionProEngine : IVisualEngine, ICalibrationVisionProvider
  22. {
  23. public string EngineName => "VisionPro9.0";
  24. // 标定工具(Cognex ToolBlock)与其持久化引用(.vpp 路径)。
  25. private CogToolBlock _calibTool;
  26. private string _toolRef;
  27. public FrameworkElement GetMainView()
  28. {
  29. return UCDispVpp.Instance;
  30. }
  31. public void ApplyHomeLayout(int frameCount, int arrange)
  32. {
  33. // RowColNumber:{画面总数, 排列方式}——内部按最优行列铺设 VppWindow 网格
  34. // frameCount=0 时清空画面区(主页面不显示画面框)
  35. UCDispVpp.Instance.RowColNumber = new[] { frameCount, arrange };
  36. }
  37. public FrameworkElement GetCalibrationView()
  38. {
  39. return new VppCalibrationPage();
  40. }
  41. /// <summary>设置指定画面框的标题(画面名称);index 越界时静默忽略。</summary>
  42. public void SetFrameCaption(int index, string name)
  43. {
  44. if (index < 0 || UCDispVpp.Instance.vppWindow.Count <= index) return;
  45. UCDispVpp.Instance.vppWindow[index].SetCaption(name);
  46. }
  47. /// <summary>设置指定画面框的状态圆点显隐;index 越界时静默忽略。</summary>
  48. public void SetFrameDotVisible(int index, bool visible)
  49. {
  50. if (index < 0 || UCDispVpp.Instance.vppWindow.Count <= index) return;
  51. UCDispVpp.Instance.vppWindow[index].SetStatusDotVisible(visible);
  52. }
  53. #region ICalibrationVisionProvider
  54. /// <summary>当前标定工具句柄(Cognex CogToolBlock)。</summary>
  55. public object CurrentTool => _calibTool;
  56. /// <summary>标定工具持久化引用(.vpp 路径)。</summary>
  57. public string ToolRef
  58. {
  59. get { return _toolRef; }
  60. set { _toolRef = value; }
  61. }
  62. /// <summary>
  63. /// 在图像上运行标定 ToolBlock,返回特征点像素坐标。
  64. /// 约定:ToolBlock 输入终端 "InputImage",输出终端 "Found"(bool)、"Point"(字符串 "x,y[,angle]")。
  65. /// </summary>
  66. public Task<(bool found, double px, double py, double angle)> FindCalibPoint(GenImage image)
  67. {
  68. return Task.Run(() =>
  69. {
  70. try
  71. {
  72. if (_calibTool == null || image == null) return (false, 0d, 0d, 0d);
  73. ICogImage cog = GenImageConverter.ToCogImage(image);
  74. if (cog == null) return (false, 0d, 0d, 0d);
  75. var input = _calibTool.Inputs["InputImage"];
  76. if (input != null) input.Value = cog;
  77. _calibTool.Run();
  78. CogToolBlockTerminalCollection outputs = _calibTool.Outputs;
  79. var foundTerminal = outputs["Found"];
  80. bool found = foundTerminal != null && foundTerminal.Value != null && Convert.ToBoolean(foundTerminal.Value);
  81. if (!found) return (false, 0d, 0d, 0d);
  82. double px = 0, py = 0, angle = 0;
  83. var pointTerminal = outputs["Point"];
  84. if (pointTerminal != null && pointTerminal.Value != null)
  85. {
  86. ParsePoint(pointTerminal.Value, ref px, ref py, ref angle);
  87. }
  88. return (true, px, py, angle);
  89. }
  90. catch
  91. {
  92. return (false, 0d, 0d, 0d);
  93. }
  94. });
  95. }
  96. /// <summary>畸变校正:VisionPro 引擎暂原样返回(如需棋盘格校正后续在此接入)。</summary>
  97. public Task<GenImage> Undistort(GenImage image)
  98. {
  99. return Task.FromResult(image);
  100. }
  101. /// <summary>从 .vpp 引用加载标定 ToolBlock;引用为空或加载失败时新建空 ToolBlock。</summary>
  102. public void LoadTool(string toolRef)
  103. {
  104. _toolRef = toolRef;
  105. _calibTool = null;
  106. try
  107. {
  108. if (!string.IsNullOrEmpty(toolRef) && File.Exists(toolRef))
  109. {
  110. _calibTool = CogSerializer.LoadObjectFromFile(toolRef) as CogToolBlock;
  111. }
  112. }
  113. catch
  114. {
  115. _calibTool = null;
  116. }
  117. if (_calibTool == null) _calibTool = new CogToolBlock();
  118. }
  119. /// <summary>将当前标定 ToolBlock 保存到目录下的 CalibTool.vpp,返回该路径作为持久化引用。</summary>
  120. public string SaveTool(string directory)
  121. {
  122. if (_calibTool == null) return _toolRef;
  123. try
  124. {
  125. if (!Directory.Exists(directory)) Directory.CreateDirectory(directory);
  126. string path = Path.Combine(directory, "CalibTool.vpp");
  127. CogSerializer.SaveObjectToFile(_calibTool, path);
  128. _toolRef = path;
  129. return path;
  130. }
  131. catch
  132. {
  133. return _toolRef;
  134. }
  135. }
  136. private static void ParsePoint(object value, ref double px, ref double py, ref double angle)
  137. {
  138. string s = value.ToString();
  139. if (string.IsNullOrWhiteSpace(s)) return;
  140. string[] items = s.Split(',');
  141. if (items.Length >= 2
  142. && double.TryParse(items[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out double x)
  143. && double.TryParse(items[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out double y))
  144. {
  145. px = x; py = y;
  146. }
  147. if (items.Length >= 3
  148. && double.TryParse(items[2].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out double a))
  149. {
  150. angle = a;
  151. }
  152. }
  153. #endregion
  154. }
  155. }